Hi,

This patch fixes PR124026.

Regstrapped on x86_64-linux-gnu, committed to mainline, and backported
to releases/gcc-13, gcc-14, and gcc-15.

Regards,
Iain.

---
        PR d/124026

gcc/d/ChangeLog:

        * expr.cc (ExprVisitor::visit (FuncExp *)): Always convert function
        literal to a delegate if the expression expects one.
---
 gcc/d/expr.cc | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index d05a12d5d09..8c068b083e5 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -1871,27 +1871,31 @@ public:
     /* Compile the declaration.  */
     build_lambda_tree (e->fd, e->type->toBasetype ());
 
-    /* If nested, this will be a trampoline.  */
-    if (e->fd->isNested ())
-      {
-       tree func = build_address (get_symbol_decl (e->fd));
-       tree object;
+    tree func = build_address (get_symbol_decl (e->fd));
+    Type *tb = e->type->toBasetype ();
 
-       if (this->constp_)
+    /* If a delegate is expected, the literal will be inferred as a delegate
+       even if it accesses no variables from an enclosing function.  */
+    if (tb->ty == TY::Tdelegate)
+      {
+       /* Static delegate variables have no context pointer.  */
+       if (this->constp_ || !e->fd->isNested ())
          {
-           /* Static delegate variables have no context pointer.  */
-           object = null_pointer_node;
-           this->result_ = build_method_call (func, object, e->fd->type);
+           this->result_ = build_method_call (func, null_pointer_node,
+                                              e->fd->type);
            TREE_CONSTANT (this->result_) = 1;
          }
        else
          {
-           object = get_frame_for_symbol (e->fd);
+           gcc_assert (e->fd->isNested ());
+           tree object = get_frame_for_symbol (e->fd);
            this->result_ = build_method_call (func, object, e->fd->type);
          }
       }
     else
       {
+       /* The function literal is a function pointer.  */
+       gcc_assert (tb->ty == TY::Tpointer);
        this->result_ = build_nop (build_ctype (e->type),
                                   build_address (get_symbol_decl (e->fd)));
       }
diff --git a/gcc/testsuite/gdc.dg/pr124026.d b/gcc/testsuite/gdc.dg/pr124026.d
new file mode 100644
index 00000000000..48a3e13eded
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr124026.d
@@ -0,0 +1,21 @@
+// { dg-do compile }
+struct UDA
+{
+    int delegate() foo;
+}
+
+static UDA getUDA(alias S)()
+{
+    return __traits(getAttributes, S)[0];
+}
+
+struct S124026
+{
+    @UDA({ return 42; }) int a;
+}
+
+void f124026()
+{
+    S124026 m;
+    enum uda = getUDA!(m.a);
+}
-- 
2.43.0

Reply via email to