Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
[expr.prim.splice]/2 doesn't actually allow templates in
a splice-expression of the form splice-specifier, but we are not
currently detecting that in check_splice_expr, which can mean
that we crash if the user attempts to use such a splice.

As an extension, we allow function templates, and assume that the
user forgot to type 'template'.

mangle3.C was testing invalid cases so remove that.

        PR c++/125631

gcc/cp/ChangeLog:

        * reflect.cc (check_splice_expr): Reject (non-function) templates.

gcc/testsuite/ChangeLog:

        * g++.dg/reflect/crash6.C: Adjust dg-error.
        * g++.dg/reflect/mangle3.C: Remove some invalid tests.
        * g++.dg/reflect/error15.C: New test.
---
 gcc/cp/reflect.cc                      | 15 +++++
 gcc/testsuite/g++.dg/reflect/crash6.C  |  4 +-
 gcc/testsuite/g++.dg/reflect/error15.C | 84 ++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/reflect/mangle3.C |  9 ---
 4 files changed, 101 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/reflect/error15.C

diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 8bf518df64f..62c4e168108 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -9362,6 +9362,21 @@ check_splice_expr (location_t loc, location_t start_loc, 
tree t,
       return false;
     }
 
+  /* [expr.prim.splice]/2 doesn't allow for the splice-expression of the form
+     splice-specifier to designate a template.  But we accept a function
+     template here as an extension, because it would be valid if the 'template'
+     keyword were present.  */
+  if (!template_p
+      && !targs_p
+      && !member_access_p
+      && TREE_CODE (t) == TEMPLATE_DECL
+      && !DECL_FUNCTION_TEMPLATE_P (t))
+    {
+      if (complain_p)
+       error_at (loc, "cannot use template %qE in a splice expression", t);
+      return false;
+    }
+
   /* [expr.prim.splice]/2: "The expression is ill-formed if S [the construct
      designated by splice-specifier] is
      -- a local entity such that there is a lambda scope that intervenes
diff --git a/gcc/testsuite/g++.dg/reflect/crash6.C 
b/gcc/testsuite/g++.dg/reflect/crash6.C
index a455a61cd65..4dd2f5fc7b8 100644
--- a/gcc/testsuite/g++.dg/reflect/crash6.C
+++ b/gcc/testsuite/g++.dg/reflect/crash6.C
@@ -10,8 +10,8 @@ template<info R>
 void
 f ()
 {
-  [:R:] r; // { dg-error "expected" }
-  [:R:]<int> r; // { dg-error "expected" }
+  [:R:] r; // { dg-error "expected|cannot use template" }
+  [:R:]<int> r; // { dg-error "expected|cannot use template" }
 }
 
 void
diff --git a/gcc/testsuite/g++.dg/reflect/error15.C 
b/gcc/testsuite/g++.dg/reflect/error15.C
new file mode 100644
index 00000000000..a2fdf4a52ed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/error15.C
@@ -0,0 +1,84 @@
+// PR c++/125631
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <tuple>
+
+template<auto Templ, class Tuple>
+const auto
+make_from_tuple (Tuple&& t)
+{
+  return [:Templ:]{}; // { dg-error "expected|cannot use template .std::tuple. 
in a splice expression" }
+}
+auto p = make_from_tuple<^^std::tuple>(std::tuple());
+
+template<auto N> int tv;
+template<auto N> concept C = requires { true; };
+template<typename T> struct S { };
+template<typename T>
+using A = S<T>;
+template<typename> using I = int;
+
+template<auto R>
+void
+g1 ()
+{
+  auto a = [:R:];  // { dg-error "cannot use template .tv<N>. in a splice 
expression" }
+}
+
+template<auto R>
+void
+g2 ()
+{
+  auto a = [:R:];  // { dg-error "cannot use template .C. in a splice 
expression" }
+}
+
+template<auto R>
+void
+g3 ()
+{
+  auto a = [:R:];  // { dg-error "cannot use template .S. in a splice 
expression" }
+}
+
+template<auto R>
+void
+g4 ()
+{
+  auto a = [:R:];  // { dg-error "cannot use template .A. in a splice 
expression" }
+}
+
+template<auto R>
+void
+g5 ()
+{
+  auto a = [:R:];  // { dg-error "cannot use template .I. in a splice 
expression" }
+}
+
+template<template<class> class TT>
+void
+g6 ()
+{
+  auto x = [:^^TT:];  // { dg-error "cannot use template .S. in a splice 
expression" }
+}
+
+template<auto R>
+void
+g7 ()
+{
+  &[:R:];  // { dg-error "cannot use template .S. in a splice expression" }
+}
+
+template<auto R> auto g8 () -> decltype([:R:]);        // { dg-error "cannot 
use template .tv<N>. in a splice expression" }
+
+void
+h ()
+{
+  g1<^^tv>();
+  g2<^^C>();
+  g3<^^S>();
+  g4<^^A>();
+  g5<^^I>();
+  g6<S>();
+  g7<^^S>();
+  g8<^^tv>(); // { dg-error "no matching function" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/mangle3.C 
b/gcc/testsuite/g++.dg/reflect/mangle3.C
index 390f249fb0c..1e1302d1377 100644
--- a/gcc/testsuite/g++.dg/reflect/mangle3.C
+++ b/gcc/testsuite/g++.dg/reflect/mangle3.C
@@ -15,8 +15,6 @@ using Alias = int;
 template<auto>
 struct TCls { };
 
-template <auto> int TVar;
-
 template<typename T>
 struct B {
   T t;
@@ -41,7 +39,6 @@ namespace N {
 }
 
 namespace NSAlias = N;
-template <auto> concept Concept = requires { true; };
 constexpr auto ctx = std::meta::access_context::current ();
 
 template<typename T>
@@ -160,18 +157,12 @@ g (int p)
 // { dg-final { scan-assembler "_Z2f4ILDmsb2a1EE4TClsIXszDST_EEEv" } }
   f4<^^A>();
 // { dg-final { scan-assembler "_Z2f4ILDmen4Enum1AEE4TClsIXszDST_EEEv" } }
-  f4<^^TVar>();
-// { dg-final { scan-assembler "_Z2f4ILDmvt4TVarEE4TClsIXszDST_EEEv" } }
   f5<^^i>();
 // { dg-final { scan-assembler "_Z2f5ILDmvr1iEEDtDST_EEv" } }
   f5<^^a1>();
 // { dg-final { scan-assembler "_Z2f5ILDmsb2a1EEDtDST_EEv" } }
   f5<^^A>();
 // { dg-final { scan-assembler "_Z2f5ILDmen4Enum1AEEDtDST_EEv" } }
-  f5<^^TVar>();
-// { dg-final { scan-assembler "_Z2f5ILDmvt4TVarEEDtDST_EEv" } }
-  f5<^^Concept>();
-// { dg-final { scan-assembler "_Z2f5ILDmco7ConceptEEDtDST_EEv" } }
   f5<^^p>();
 // { dg-final { scan-assembler "_Z2f5ILDmvrZ1giE1pEEDtDST_EEv" } }
   f5<std::meta::reflect_constant (42)>();

base-commit: 9b2bbe9104aef2e6bd9e8d7ace5fed3e2726f4d3
-- 
2.56.0

Reply via email to