Here, in the thunk returned from the captureless lambda conversion to
pointer-to-function, we try to pass through invisible reference parameters
by reference, without doing a copy. The empty class copy optimization was
messing that up.
Tested x86_64-pc-linux-gnu, applying to trunk.
gcc/cp/ChangeLog:
PR c++/98326
PR c++/20408
* cp-gimplify.c (simple_empty_class_p): Don't touch an invisiref
parm.
gcc/testsuite/ChangeLog:
PR c++/98326
* g++.dg/cpp1y/lambda-generic-empty1.C: New test.
---
gcc/cp/cp-gimplify.c | 12 ++++++++++++
gcc/testsuite/g++.dg/cpp1y/lambda-generic-empty1.C | 9 +++++++++
2 files changed, 21 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/cpp1y/lambda-generic-empty1.C
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index 4d0e92c3321..1c5e15b957f 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -324,6 +324,18 @@ simple_empty_class_p (tree type, tree op, tree_code code)
&& TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
/* The TARGET_EXPR is itself a simple copy, look through it. */
return simple_empty_class_p (type, TARGET_EXPR_INITIAL (op), code);
+
+ if (TREE_CODE (op) == PARM_DECL
+ && TREE_ADDRESSABLE (TREE_TYPE (op)))
+ {
+ tree fn = DECL_CONTEXT (op);
+ if (DECL_THUNK_P (fn)
+ || lambda_static_thunk_p (fn))
+ /* In a thunk, we pass through invisible reference parms, so this isn't
+ actually a copy. */
+ return false;
+ }
+
return
(TREE_CODE (op) == EMPTY_CLASS_EXPR
|| code == MODIFY_EXPR
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-empty1.C
b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-empty1.C
new file mode 100644
index 00000000000..ffb0cf149ce
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-empty1.C
@@ -0,0 +1,9 @@
+// PR c++/98326
+// { dg-do compile { target c++14 } }
+
+struct A {
+ A() = default;
+ A(const A&) {}
+};
+
+void (*fptr)(A) = [](auto){};
base-commit: 2da7ce23cfd81b67f77dc102d6f97dd19363b5f4
prerequisite-patch-id: 67efffa865b1469c2b63fe7a6ae9fec692c63079
--
2.27.0