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

-- >8 --
In both testcases the problem is that reflect_current_scope doesn't
handle local classes in a function.  We just use current_function_decl
but that then means that current_class throws and
access_context::current gives the enclosing function.

        PR c++/125808
        PR c++/125519

gcc/cp/ChangeLog:

        * reflect.cc (reflect_current_scope): Handle local classes.

gcc/testsuite/ChangeLog:

        * g++.dg/reflect/current_class3.C: New test.
        * g++.dg/reflect/current_class4.C: New test.
        * g++.dg/reflect/current_class5.C: New test.
        * g++.dg/reflect/current_function3.C: New test.
        * g++.dg/reflect/current_function4.C: New test.
        * g++.dg/reflect/current_namespace2.C: New test.
---
 gcc/cp/reflect.cc                             | 18 +++++--
 gcc/testsuite/g++.dg/reflect/current_class3.C | 20 ++++++++
 gcc/testsuite/g++.dg/reflect/current_class4.C | 17 +++++++
 gcc/testsuite/g++.dg/reflect/current_class5.C | 51 +++++++++++++++++++
 .../g++.dg/reflect/current_function3.C        | 36 +++++++++++++
 .../g++.dg/reflect/current_function4.C        | 17 +++++++
 .../g++.dg/reflect/current_namespace2.C       | 20 ++++++++
 7 files changed, 176 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/reflect/current_class3.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/current_class4.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/current_class5.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/current_function3.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/current_function4.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/current_namespace2.C

diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 4137fb64e75..afdf0226ec0 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -6652,10 +6652,22 @@ reflect_current_scope (location_t loc, const 
constexpr_ctx *ctx, tree call,
                       bool *non_constant_p, const char *name)
 {
   tree scope = cxx_constexpr_caller (ctx);
-  /* Ignore temporary current_function_decl changes caused by
-     push_access_scope.  */
   if (scope == NULL_TREE && current_function_decl)
-    scope = current_function_decl_without_access_scope ();
+    {
+      /* Handle local classes.  We need to make sure that we are inside
+        a class that is local to the current function, and not inside one
+        of that class's member functions or friends (kind of like what
+        current_scope does).  */
+      if (current_class_type
+         && !LAMBDA_TYPE_P (current_class_type)
+         && decl_function_context (TYPE_MAIN_DECL (current_class_type))
+            == current_function_decl)
+       scope = current_class_type;
+      else
+       /* Ignore temporary current_function_decl changes caused by
+          push_access_scope.  */
+       scope = current_function_decl_without_access_scope ();
+    }
   /* [meta.reflection.access.context]/(5.1.2): Otherwise, if an initialization
      by an inherited constructor is using I, a point whose immediate scope is
      the class scope corresponding to C.  */
diff --git a/gcc/testsuite/g++.dg/reflect/current_class3.C 
b/gcc/testsuite/g++.dg/reflect/current_class3.C
new file mode 100644
index 00000000000..6f70491232c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/current_class3.C
@@ -0,0 +1,20 @@
+// PR c++/125808
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+struct A {
+  void f([:std::meta::current_class():]) {}
+};
+
+static_assert (type_of (parameters_of (^^A::f)[0]) == ^^A);
+
+int
+main ()
+{
+  struct B {
+    void f([:std::meta::current_class():]) {}
+  };
+  static_assert (type_of (parameters_of (^^B::f)[0]) == ^^B);
+}
diff --git a/gcc/testsuite/g++.dg/reflect/current_class4.C 
b/gcc/testsuite/g++.dg/reflect/current_class4.C
new file mode 100644
index 00000000000..36046c1880d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/current_class4.C
@@ -0,0 +1,17 @@
+// PR c++/125519
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+template<auto V> struct A { static constexpr auto value = V; };
+
+consteval std::meta::info test() {
+    struct Local {
+        using T = A<std::meta::access_context::current().scope()>;
+        using U = A<std::meta::current_class()>;
+    };
+    return Local::T::value;
+}
+
+static_assert(std::meta::identifier_of(test()) == "Local");
diff --git a/gcc/testsuite/g++.dg/reflect/current_class5.C 
b/gcc/testsuite/g++.dg/reflect/current_class5.C
new file mode 100644
index 00000000000..90d6460ed6d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/current_class5.C
@@ -0,0 +1,51 @@
+// PR c++/125519
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+template<auto V> struct A { static constexpr auto value = V; };
+
+void
+f ()
+{
+  [] {
+    constexpr auto fn = current_function ();
+    static_assert (current_class () == parent_of (fn));
+    static_assert (!has_identifier (current_class ()));
+  } ();
+
+  [] {
+    struct L {
+      static_assert (current_class () == ^^L);
+      static_assert (access_context::current ().scope () == ^^L);
+      struct N {
+       static_assert (current_class () == ^^N);
+      };
+    };
+  } ();
+
+  struct S {
+    using T = A<[] { return current_class (); } ()>;
+  };
+  static_assert (S::T::value != ^^S);
+  static_assert (!has_identifier (S::T::value));
+}
+
+template<typename>
+void
+ft ()
+{
+  struct S {
+    static constexpr bool test ()
+    {
+      return current_class () == ^^S;
+    }
+    static_assert (current_class () == ^^S);
+  };
+  static_assert (S::test ());
+}
+
+template void ft<int> ();
diff --git a/gcc/testsuite/g++.dg/reflect/current_function3.C 
b/gcc/testsuite/g++.dg/reflect/current_function3.C
new file mode 100644
index 00000000000..3c2a9d65f4c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/current_function3.C
@@ -0,0 +1,36 @@
+// PR c++/125519
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+void
+f ()
+{
+  struct S {
+    static constexpr bool g (bool b = current_function () == ^^f)
+    { return b; }
+  };
+  static_assert (S::g ());
+}
+
+template<typename T>
+void
+ft ()
+{
+  // Default arguments: eval-point is the call that uses the default argument.
+  struct S {
+    static constexpr bool h (bool b = current_function () == ^^ft<T>)
+    { return b; }
+
+    static constexpr bool k (bool b = current_function () == ^^S::m)
+    { return b; }
+
+    void m () { static_assert (k ()); }
+  };
+  static_assert (S::h ());
+}
+
+template void ft<int> ();
diff --git a/gcc/testsuite/g++.dg/reflect/current_function4.C 
b/gcc/testsuite/g++.dg/reflect/current_function4.C
new file mode 100644
index 00000000000..62ca0e12139
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/current_function4.C
@@ -0,0 +1,17 @@
+// PR c++/125519
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+template<auto V> struct A { static constexpr auto value = V; };
+
+void
+f ()
+{
+  struct S {
+    using U = A<current_function ()>;  // { dg-error "does not represent a 
function" }
+  };
+}
diff --git a/gcc/testsuite/g++.dg/reflect/current_namespace2.C 
b/gcc/testsuite/g++.dg/reflect/current_namespace2.C
new file mode 100644
index 00000000000..c9818755bd9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/current_namespace2.C
@@ -0,0 +1,20 @@
+// PR c++/125519
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+using namespace std::meta;
+
+template<auto V> struct A { static constexpr auto value = V; };
+
+namespace N {
+void
+f ()
+{
+  struct S {
+    using U = A<current_namespace ()>;
+  };
+  static_assert (S::U::value == ^^N);
+}
+}

base-commit: 471f13d60084a07a69315459d728a2f5bec0af83
-- 
2.56.0

Reply via email to