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