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" } }