pop_namespace ();
}
+/* Ensure the type of DECL is fully resolved by performing return
+ type deduction and deferred noexcept instantiation. */
+
+static void
+resolve_type_of_reflected_decl (tree decl)
+{
+ /* Quietly calling mark_used in an unevaluated context will perform
+ all necessary checks and instantiations while suppressing constraint
+ unsatisfaction and deletedness diagnostics. */
+ cp_unevaluated u;
+ mark_used (decl, tf_none);
+}
+
/* Create a REFLECT_EXPR expression of kind KIND around T. */
static tree
t = resolve_nondeduced_context_or_error (t, tf_warning_or_error);
/* The argument could have a deduced return type, so we need to
instantiate it now to find out its type. */
- if (!mark_used (t))
- return error_mark_node;
+ resolve_type_of_reflected_decl (t);
/* Avoid -Wunused-but-set* warnings when a variable or parameter
is just set and reflected. */
if (VAR_P (t) || TREE_CODE (t) == PARM_DECL)
{
if (DECL_CONSTRUCTOR_P (r) || DECL_DESTRUCTOR_P (r))
return false;
+ resolve_type_of_reflected_decl (r);
if (undeduced_auto_decl (r))
return false;
return true;
if (fn == error_mark_node)
return boolean_false_node;
fn = resolve_nondeduced_context_or_error (fn, tf_none);
+ fn = MAYBE_BASELINK_FUNCTIONS (fn);
+ resolve_type_of_reflected_decl (fn);
if (fn == error_mark_node || undeduced_auto_decl (fn))
return boolean_false_node;
return boolean_true_node;
|| TREE_CODE (r) == FIELD_DECL
|| TREE_CODE (r) == NAMESPACE_DECL)
return true;
- if (VAR_OR_FUNCTION_DECL_P (r) && !undeduced_auto_decl (r))
- return true;
+ if (VAR_OR_FUNCTION_DECL_P (r))
+ {
+ resolve_type_of_reflected_decl (r);
+ if (!undeduced_auto_decl (r))
+ return true;
+ }
}
return false;
}
--- /dev/null
+// [meta.reflection.substitute] Example 1
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+template<class T>
+auto fn1();
+
+static_assert(!can_substitute(^^fn1, {^^int}));
+constexpr auto r1 = substitute(^^fn1, {^^int}); // { dg-error "can_substitute returned false" }
+
+template<class T>
+auto fn2() {
+ static_assert(false); // { dg-error "assert" }
+ return T{};
+}
+
+constexpr bool r2 = can_substitute(^^fn2, {^^int}); // { dg-message "required from here" }
--- /dev/null
+// PR c++/124628
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+template<class T> void f();
+
+template<class T>
+struct A {
+ void g() noexcept(noexcept(T{}));
+ auto h() { return T{}; }
+ static inline auto m = T{};
+ // A& operator=(const A&) noexcept;
+ // A& operator=(A&&) noexcept;
+};
+
+int main() {
+ constexpr auto ac = std::meta::access_context::current();
+ template for (constexpr auto mem : define_static_array(members_of(^^A<int>, ac)))
+ if constexpr (!is_constructor(mem) && !is_destructor(mem))
+ f<typename [:type_of(mem):]>();
+}
+
+// { dg-final { scan-assembler _Z1fIDoFvvEEvv } } void f<void () noexcept>()
+// { dg-final { scan-assembler _Z1fIFivEEvv } } void f<int ()>()
+// { dg-final { scan-assembler _Z1fIiEvv } } void f<int>()
+// { dg-final { scan-assembler _Z1fIDoFR1AIiERKS1_EEvv } } void f<A<int>& (A<int> const&) noexcept>()
+// { dg-final { scan-assembler _Z1fIDoFR1AIiEOS1_EEvv } } void f<A<int>& (A<int>&&) noexcept>()