This patch addresses a compiler incompatibility with non-capturing lambdas. Specifically, when a lambda's functions are comdat, we place the static _FUN function in the same comdat group as the operator() function.

This breaks link compatibility with clang, where the static function is named __invoker and not placed in the same group. The case we hit was a link failure when the clang-generated comdat group was chosen and the _FUN symbol dropped.

I'm not sure of the rationale of placing them in the same group. The inliner would still be correct to inline the operator() it can see into the _FUN body, as all comdat groups are supposed to be equivalent, so even if a clang-generated operator() ends up in the executable, that's fine to interoperate with a gcc-generated _FUN. (we did initially think this was an LTO bug when it applied identical code folding to the two functions, as they are indeed identical)

inter-compiler interoperation of capturing lambdas is a different issue -- not sure if the ABI mandates layout. But that's not relevant in this case as the lambda is an empty object, and that's the only case we can generate a static _FUN executor.

Jason, any objections for trunk?

nathan
--
Nathan Sidwell
2019-03-20  Nathan Sidwell  <nat...@acm.org>

	* lambda.c (maybe_add_lambda_conv_op): Don't add to comdat group.

	* g++.dg/abi/lambda-static-1.C: New.

Index: cp/lambda.c
===================================================================
--- cp/lambda.c	(revision 269818)
+++ cp/lambda.c	(working copy)
@@ -1267,12 +1267,6 @@ maybe_add_lambda_conv_op (tree type)
 
   start_preparsed_function (statfn, NULL_TREE,
 			    SF_PRE_PARSED | SF_INCLASS_INLINE);
-  if (DECL_ONE_ONLY (statfn))
-    {
-      /* Put the thunk in the same comdat group as the call op.  */
-      cgraph_node::get_create (statfn)->add_to_same_comdat_group
-	(cgraph_node::get_create (callop));
-    }
   tree body = begin_function_body ();
   tree compound_stmt = begin_compound_stmt (0);
   if (!generic_lambda_p)
Index: testsuite/g++.dg/abi/lambda-static-1.C
===================================================================
--- testsuite/g++.dg/abi/lambda-static-1.C	(revision 0)
+++ testsuite/g++.dg/abi/lambda-static-1.C	(working copy)
@@ -0,0 +1,25 @@
+// { dg-do compile { target { c++14 && comdat_group } } }
+// { dg-additional-options -fno-inline }
+
+inline auto lamby () 
+{
+  return [] {};
+}
+
+void direct ()
+{
+  lamby ()();
+}
+
+void indirect ()
+{
+  void (*invoke) () = lamby ();
+
+  invoke ();
+}
+
+// The call operator and the static invoker should be comdat, but not
+// the same group.  (that would be a compiler incompatibility)
+
+// { dg-final { scan-assembler ".section\[\t ]*.text._ZZ5lambyvENKUlvE_clEv,\[^\n\r]*,_ZZ5lambyvENKUlvE_clEv,comdat" } }
+// { dg-final { scan-assembler ".section\[\t ]*.text._ZZ5lambyvENUlvE_4_FUNEv,\[^\n\r]*,_ZZ5lambyvENUlvE_4_FUNEv,comdat" } }

Reply via email to