On 1/21/26 3:58 AM, Marek Polacek wrote:
On Fri, Jan 09, 2026 at 01:27:44PM +0800, Jason Merrill wrote:
On 1/9/26 3:24 AM, Marek Polacek wrote:
On Tue, Dec 16, 2025 at 10:48:40PM +0700, Jason Merrill wrote:
On 11/15/25 8:36 AM, Marek Polacek wrote:
+static tree
+get_info (const constexpr_ctx *ctx, tree call, int n, bool *non_constant_p,
+ bool *overflow_p, tree *jump_target)
+{
+ gcc_checking_assert (call_expr_nargs (call) > n);
+ tree info = get_nth_callarg (call, n);
+ gcc_checking_assert (REFLECTION_TYPE_P (TREE_TYPE (info)));
+ info = cxx_eval_constant_expression (ctx, info, vc_prvalue,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (*jump_target)
+ return NULL_TREE;
+ if (!REFLECT_EXPR_P (info))
+ {
+ *non_constant_p = true;
+ return NULL_TREE;
+ }
+ return info;
+}
+
+/* Try to get the underlying FUNCTION_DECL from reflection if any,
+ otherwise return R. */
Please say more about why get_first_fn isn't suitable (if it isn't).
The problem is that get_fns asserts that there was an overload set,
but often there won't be. What I could do is to introduce
maybe_get_first_fn that uses maybe_get_fns.
Sounds good.
Posted a patch for this:
<https://gcc.gnu.org/pipermail/gcc-patches/2026-January/706367.html>
+static tree
+eval_is_override (tree r)
+{
+ r = maybe_get_reflection_fndecl (r);
+ if (TREE_CODE (r) == FUNCTION_DECL
+ && DECL_CLASS_SCOPE_P (r)
+ && !DECL_CONSTRUCTOR_P (r)
+ && (IDENTIFIER_VIRTUAL_P (DECL_NAME (r))
+ || DECL_CONV_FN_P (r))
+ && !DECL_STATIC_FUNCTION_P (r)
I'd think checking DECL_VIRTUAL_P could replace most of the above
conditions.
Changed to use DECL_VIRTUAL_P in
<https://forge.sourceware.org/marek/gcc/commit/9a040fb9c52c963ac5cf5ecffa4f4a0769446b24>
Do we still need to check DECL_CONV_FN_P?
No, removed in
<https://forge.sourceware.org/marek/gcc/commit/7982d483b57952ca9005c0b131fbccb432ed2d80>
+/* Process std::meta::is_user_provided.
+ Returns: true if r represents a function that is user-provided.
+ Otherwise, false. */
+
+static tree
+eval_is_user_provided (tree r)
+{
+ r = maybe_get_reflection_fndecl (r);
+ if (TREE_CODE (r) == FUNCTION_DECL
+ && user_provided_p (r)
+ // TODO: user_provided_p is false for non-members defaulted on
+ // first declaration.
Maybe we could set DECL_INITIALIZED_IN_CLASS_P for non-member functions, too
(and probably rename it).
I suppose, but I'd rather not do it as part of the Reflection patch.
Fair...
+ && (!DECL_NAMESPACE_SCOPE_P (r) || !DECL_DELETED_FN (r)))
...but then I'd rather not halfway work around the issue in the reflection
patch, either.
I'm a little worried about changing DECL_INITIALIZED_IN_CLASS_P in
stage 4. What if I opened an internal-improvement PR for this?
Actually I think we don't need to mess with DECL_INITIALIZED_IN_CLASS_P,
because any function deleted after its first declaration is ill-formed
rather than user-provided.
void f();
void f() = delete; // error, not first declaration
so we can just fix user_provided_p.
+ if (TREE_CODE (r) == CONST_DECL)
+ return boolean_true_node;
+ else
+ return boolean_false_node;
+}
+
+/* Process std::meta::has_internal_linkage.
+ Returns: true if r represents a variable, function, type, template, or
+ namespace whose name has internal linkage. Otherwise, false. */
+
+static tree
+eval_has_internal_linkage (tree r, reflect_kind kind)
+{
+ if (eval_is_variable (r, kind) == boolean_false_node
+ && eval_is_function (r) == boolean_false_node
+ && eval_is_type (r) == boolean_false_node
+ && eval_is_template (r) == boolean_false_node
+ && eval_is_namespace (r) == boolean_false_node)
+ return boolean_false_node;
+ r = maybe_get_reflection_fndecl (r);
+ r = STRIP_TEMPLATE (r);
+ if (TYPE_P (r))
+ {
+ if (TYPE_NAME (r) == NULL_TREE
+ || !DECL_P (TYPE_NAME (r))
+ || (!DECL_IMPLICIT_TYPEDEF_P (TYPE_NAME (r))
+ && TYPE_NAME (r) == TYPE_NAME (TYPE_MAIN_VARIANT (r))
+ && !TYPE_MAIN_DECL (r)))
It seems simpler to go directly to TYPE_NAME (TYPE_MAIN_VARIANT (r)) to find
the name with linkage, and probably also check OVERLOAD_TYPE_P.
I didn't understand this.
I was thinking type_linkage_name would be
if (!OVERLOAD_TYPE_P (t))
return NULL_TREE;
return TYPE_NAME (TYPE_MAIN_VARIANT (t));
That breaks:
struct cls { };
using alias = cls;
template<typename> struct cls_tmpl {};
template<typename T> using cls_tmpl_alias = cls_tmpl<T>;
static_assert (!has_linkage (^^alias));
static_assert (!has_linkage (^^cls_tmpl_alias<int>));
Currently, for a RECORD_TYPE alias we return a TYPE_DECL alias,
but with this patch we return a TYPE_DECL cls (and same for the
alias template case).
Ah, so type_linkage_name isn't a great name, since what it does is
specific to reflection alias handling. What it does is filter out types
with no name, a non-DECL name (which is probably unnecessary, such types
shouldn't be exposed to user code), and typedefs for linkage purposes.
It seems clearer to return null for all typedef_variant_p rather than
just for typedefs for linkage purposes.
So,
if (OVERLOAD_TYPE_P (t)
&& !typedef_variant_p (t))
return TYPE_NAME (t);
return NULL_TREE;
Jason