Each lambda that can be converted to a plain function pointer has a
thunk generated for it, which invokes the body of the lambda function.

When a section attribute is added to a lambda function, it only applies
to the body of the lambda function, and not the thunk. When a lambda is
only ever used by converting it to a function pointer, the body of the
lambda is inlined into this thunk. As a result, the section attribute
is effectively ignored: the function it applied to is gone, and the thunk
does not have the section attribute applied to it either.

This patch checks if a section attribute is present on a lambda, and
applies it to the thunk.

The motivation for this change is embedded devices where most code is
executed from flash, but code which must execute while the device is
being reprogrammed can be moved to RAM by placing it in a different
section.

This patch was tested with bootstrapping on x86-64 under WSL, and
the newly added test was also run on 32-bit ARM.

gcc/cp/ChangeLog:

        * lambda.cc (maybe_add_lambda_conv_op): Don't ignore section
        attributes on lambda functions which are converted to plain
        function pointers.

gcc/testsuite/ChangeLog:

        * g++.dg/ext/attr-section-lambda.C: New test.

Signed-off-by: Campbell Suter <z...@znix.xyz>
---
 gcc/cp/lambda.cc                              |  7 ++++
 .../g++.dg/ext/attr-section-lambda.C          | 42 +++++++++++++++++++
 2 files changed, 49 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-section-lambda.C

diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index d8a15d97d..e46ecbdf2 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify.h"
 #include "target.h"
 #include "decl.h"
+#include "attribs.h"
 
 /* Constructor for a lambda expression.  */
 
@@ -1376,6 +1377,12 @@ maybe_add_lambda_conv_op (tree type)
   if (generic_lambda_p)
     fn = add_inherited_template_parms (fn, DECL_TI_TEMPLATE (callop));
 
+  if (tree a = lookup_attribute ("section", DECL_ATTRIBUTES (callop)))
+    {
+      DECL_ATTRIBUTES (fn) = attr_chainon (DECL_ATTRIBUTES (fn), a);
+      set_decl_section_name (fn, callop);
+    }
+
   if (flag_sanitize & SANITIZE_NULL)
     /* Don't UBsan this function; we're deliberately calling op() with a null
        object argument.  */
diff --git a/gcc/testsuite/g++.dg/ext/attr-section-lambda.C 
b/gcc/testsuite/g++.dg/ext/attr-section-lambda.C
new file mode 100644
index 000000000..4202ea943
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-section-lambda.C
@@ -0,0 +1,42 @@
+// Make sure that attributes apply to lambda functions properly, and aren't
+// broken by inlining with their static thunks.
+//
+// { dg-do compile { target { c++11 && named_sections } } }
+// { dg-options "-O2" }
+
+
+extern int i;
+
+void func_ptr_consumer (int (*)());
+
+void __attribute__((section(".outer_regular")))
+test_func_regular ()
+{
+  func_ptr_consumer ([]() __attribute__((section(".lambda_regular"))) {
+    return i;
+  });
+}
+
+template<typename T>
+void __attribute__((section(".outer_template"))) __attribute__((noinline))
+test_func_generic ()
+{
+  func_ptr_consumer ([]() __attribute__((section(".lambda_template"))) {
+    return i + T::a;
+  });
+}
+
+struct
+A
+{
+  static constexpr int a = 0xaabbccdd;
+};
+
+template void test_func_generic<A>();
+
+// Since we've enabled optimisations, the _FUN thunk will have absorbed the
+// lambda bodies due to inlining.
+// Thus if these sections exist, they must be from the thunk - and thus the
+// thunk has it's section set.
+// { dg-final { scan-assembler {\.(section|csect)[ \t]+"?\.lambda_regular} } }
+// { dg-final { scan-assembler {\.(section|csect)[ \t]+"?\.lambda_template} } }
-- 
2.34.1

Reply via email to