public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: auto(x) partial substitution [PR110025, PR114138]
@ 2024-02-27 20:48 Patrick Palka
  2024-02-28 21:43 ` Jason Merrill
  0 siblings, 1 reply; 6+ messages in thread
From: Patrick Palka @ 2024-02-27 20:48 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason, Patrick Palka

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk and perhaps 13?

-- >8 --

In r12-6773-g09845ad7569bac we gave CTAD placeholders a level of 0 and
ensured we never replaced them via tsubst.  It turns out that autos
representing an explicit cast need the same treatment and for the same
reason: such autos appear in an expression context and so their level
gets easily messed up after partial substitution, leading to premature
replacement via an incidental tsubst instead of via do_auto_deduction.

This patch fixes this by extending the r12-6773 approach to auto(x) and
auto{x}.

	PR c++/110025
	PR c++/114138

gcc/cp/ChangeLog:

	* cp-tree.h (make_cast_auto): Declare.
	* parser.cc (cp_parser_functional_cast): Replace a parsed auto
	with a level-less one via make_cast_auto.
	* pt.cc (find_parameter_packs_r): Don't treat level-less auto
	as a type parameter pack.
	(tsubst) <case TEMPLATE_TYPE_PARM>: Generalized CTAD placeholder
	handling to all level-less autos.
	(make_cast_auto): Define.
	(do_auto_deduction): Handle deduction of a level-less non-CTAD
	auto.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp23/auto-fncast16.C: New test.
	* g++.dg/cpp23/auto-fncast17.C: New test.
	* g++.dg/cpp23/auto-fncast18.C: New test.
---
 gcc/cp/cp-tree.h                           |  1 +
 gcc/cp/parser.cc                           | 11 ++++
 gcc/cp/pt.cc                               | 31 +++++++++-
 gcc/testsuite/g++.dg/cpp23/auto-fncast16.C | 12 ++++
 gcc/testsuite/g++.dg/cpp23/auto-fncast17.C | 15 +++++
 gcc/testsuite/g++.dg/cpp23/auto-fncast18.C | 71 ++++++++++++++++++++++
 6 files changed, 138 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast16.C
 create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast17.C
 create mode 100644 gcc/testsuite/g++.dg/cpp23/auto-fncast18.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 04c3aa6cd91..6f1da1c7bad 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7476,6 +7476,7 @@ extern tree make_decltype_auto			(void);
 extern tree make_constrained_auto		(tree, tree);
 extern tree make_constrained_decltype_auto	(tree, tree);
 extern tree make_template_placeholder		(tree);
+extern tree make_cast_auto			(void);
 extern bool template_placeholder_p		(tree);
 extern bool ctad_template_p			(tree);
 extern bool unparenthesized_id_or_class_member_access_p (tree);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 3ee9d49fb8e..1e518e6ef51 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -33314,6 +33314,17 @@ cp_parser_functional_cast (cp_parser* parser, tree type)
   if (!type)
     type = error_mark_node;
 
+  if (TREE_CODE (type) == TYPE_DECL
+      && is_auto (TREE_TYPE (type)))
+    type = TREE_TYPE (type);
+
+  if (is_auto (type)
+      && !AUTO_IS_DECLTYPE (type)
+      && !PLACEHOLDER_TYPE_CONSTRAINTS (type)
+      && !CLASS_PLACEHOLDER_TEMPLATE (type))
+    /* auto(x) and auto{x} are represented using a level-less auto.  */
+    type = make_cast_auto ();
+
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
     {
       cp_lexer_set_source_position (parser->lexer);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2803824d11e..620fe5cdbfa 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -3921,7 +3921,8 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
 	 parameter pack (14.6.3), or the type-specifier-seq of a type-id that
 	 is a pack expansion, the invented template parameter is a template
 	 parameter pack.  */
-      if (ppd->type_pack_expansion_p && is_auto (t))
+      if (ppd->type_pack_expansion_p && is_auto (t)
+	  && TEMPLATE_TYPE_LEVEL (t) != 0)
 	TEMPLATE_TYPE_PARAMETER_PACK (t) = true;
       if (TEMPLATE_TYPE_PARAMETER_PACK (t))
         parameter_pack_p = true;
@@ -16297,9 +16298,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       }
 
     case TEMPLATE_TYPE_PARM:
-      if (template_placeholder_p (t))
+      if (TEMPLATE_TYPE_LEVEL (t) == 0)
 	{
+	  /* Level-less auto must be replaced via do_auto_deduction.  */
+	  gcc_checking_assert (is_auto (t));
 	  tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (t);
+	  if (!tmpl)
+	    return t;
+
 	  tmpl = tsubst_expr (tmpl, args, complain, in_decl);
 	  if (TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)
 	    tmpl = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (tmpl);
@@ -29311,6 +29317,17 @@ template_placeholder_p (tree t)
   return is_auto (t) && CLASS_PLACEHOLDER_TEMPLATE (t);
 }
 
+/* Return an auto for an explicit cast, e.g. auto(x) or auto{x}.
+   Like CTAD placeholders, these have level 0 so that they're not
+   accidentally replaced via tsubst, and are always directly resolved
+   via do_auto_deduction.  */
+
+tree
+make_cast_auto ()
+{
+  return make_auto_1 (auto_identifier, true, /*level=*/0);
+}
+
 /* Make a "constrained auto" type-specifier. This is an auto or
   decltype(auto) type with constraints that must be associated after
   deduction.  The constraint is formed from the given concept CON
@@ -31213,7 +31230,15 @@ do_auto_deduction (tree type, tree init, tree auto_node,
 	}
     }
 
-  if (TEMPLATE_TYPE_LEVEL (auto_node) == 1)
+  if (TEMPLATE_TYPE_LEVEL (auto_node) == 0)
+    {
+      /* Level-less auto can't be replaced via tsubst, so do it directly. */
+      gcc_checking_assert (type == auto_node);
+      gcc_checking_assert (!TYPE_QUALS (type));
+      gcc_checking_assert (TREE_VEC_LENGTH (targs) == 1);
+      return TREE_VEC_ELT (targs, 0);
+    }
+  else if (TEMPLATE_TYPE_LEVEL (auto_node) == 1)
     /* The outer template arguments are already substituted into type
        (but we still may have used them for constraint checking above).  */;
   else if (context == adc_unify)
diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast16.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast16.C
new file mode 100644
index 00000000000..e2c13f6b050
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast16.C
@@ -0,0 +1,12 @@
+// PR c++/110025
+// { dg-do compile { target c++23 } }
+
+template<auto V, class = decltype(auto(V)), class = decltype(auto{V})>
+struct A { };
+
+template<auto V>
+A<V> f();
+
+int main() {
+  f<0>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast17.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast17.C
new file mode 100644
index 00000000000..25186dfdbf2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast17.C
@@ -0,0 +1,15 @@
+// PR c++/110025
+// { dg-do compile { target c++23 } }
+
+template<class...> struct tuple;
+
+template<auto V>
+using constant_t = int;
+
+template<auto... V>
+using constants_t = tuple<constant_t<auto(V)>...>;
+
+using ty0 = constants_t<>;
+using ty1 = constants_t<1>;
+using ty2 = constants_t<1, 2>;
+using ty3 = constants_t<1, 2, 3>;
diff --git a/gcc/testsuite/g++.dg/cpp23/auto-fncast18.C b/gcc/testsuite/g++.dg/cpp23/auto-fncast18.C
new file mode 100644
index 00000000000..bded5caebf4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/auto-fncast18.C
@@ -0,0 +1,71 @@
+// PR c++/114138
+// { dg-do compile { target c++23 } }
+
+namespace std {
+  template <class T>
+  T&& declval() noexcept requires true;
+
+  template <class>
+  void declval() noexcept;
+
+  namespace detail {
+    struct none_such;
+    template <class>
+    using none_such_t = none_such;
+
+    template <class T>
+      extern const none_such_t<T> _getter_for;
+
+    template <class T>
+    using _decay_t = decltype(auto(declval<T>()));
+
+    static_assert(__is_same_as(_decay_t<void>, void));
+  }
+
+  template <const auto& Fn, class... Args>
+    using _result_of_t = decltype(Fn(declval<Args>()...));
+
+  template <unsigned I, class Tuple>
+    using tuple_element_t = _result_of_t<detail::_getter_for<detail::_decay_t<Tuple>>, char(*)[I+1], Tuple>;
+
+  template <class First, class Second>
+  struct pair {
+    First first;
+    Second second;
+  };
+
+  template <class>
+    inline constexpr bool _is_pair = false;
+  
+  template <class First, class Second>
+    inline constexpr bool _is_pair<pair<First, Second>> = true;
+
+  template <class T>
+    concept Pair = _is_pair<decltype(auto(std::declval<T>()))>;
+
+  template <unsigned I, Pair P>
+    requires (I <= 1)
+  decltype(auto) get(P&& p) noexcept {
+    if constexpr (I == 0) {
+      return (static_cast<P&&>(p).first);
+    } else {
+      return (static_cast<P&&>(p).second);
+    }
+  }
+
+  namespace detail {
+    inline constexpr auto _pair_getter =
+      []<unsigned J, class Pair>(char(*)[J], Pair&& p) noexcept -> decltype(auto) {
+        return std::get<J-1>(static_cast<Pair&&>(p));
+      };
+
+    template <class First, class Second>
+      inline constexpr auto _getter_for<pair<First, Second>> = _pair_getter;
+  }
+
+}
+
+int main() {
+  static_assert(__is_same_as(int&, std::tuple_element_t<0, std::pair<int, float>&>));
+  static_assert(__is_same_as(float&&, std::tuple_element_t<1, std::pair<int, float>&&>));
+}
-- 
2.44.0.rc1.15.g4fc51f00ef


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-03-01 15:27 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-27 20:48 [PATCH] c++: auto(x) partial substitution [PR110025, PR114138] Patrick Palka
2024-02-28 21:43 ` Jason Merrill
2024-02-29 19:17   ` Patrick Palka
2024-03-01 13:39     ` Jason Merrill
2024-03-01 15:17       ` Patrick Palka
2024-03-01 15:27         ` Jason Merrill

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).