This reverts upstream commit: 94e2418780f1d13235f3e2e6e5c09dbe821c1ce3 c++: Avoid unnecessary empty class copy [94175]. which for reasons currently not understood seems to lead to various determinstic and nondeterministic stack corruption modalities during gimplification on various "Zen"-based AMD hosts, especially when building -march=znver1 targets with likewise -march=znver1 -optimized gcc builds. For gory details (mixed in with a lot of probably supersititious conclusions, ie: "GOT IT GUYS!!!! Doing a handstand and singing the Italian national anthem during the compile fixes it." -- not a real example, see Gentoo bug #724314, and its several duplicates). Somehow, adding these purportedly superflous copy steps back into the gimplification process seems to fix some or all (so far it's 1 for 1!) affected systems. Hopefully the patch is safe, but causes gcc to generate somewhat less efficient code. This is what the commitmsg implies. But, be advised that I don't personally understand the patch. I only found it myself through git bisect drudgery ... so, sorry, but I literally don't know what this patch will do to your computer! It may help, or it may well cause some kind of disaster or just do nothing... but here's hoping it works for you as well as I think it did for me! :S -gmt -- diff -uprN gcc-11.1.0.orig/gcc/cp/call.c gcc-11.1.0/gcc/cp/call.c --- gcc-11.1.0.orig/gcc/cp/call.c 2021-06-23 21:15:53.558557378 -0700 +++ gcc-11.1.0/gcc/cp/call.c 2021-06-23 21:16:51.162744564 -0700 @@ -398,10 +398,6 @@ build_call_a (tree function, int n, tree if (is_empty_class (TREE_TYPE (arg)) && simple_empty_class_p (TREE_TYPE (arg), arg, INIT_EXPR)) { - while (TREE_CODE (arg) == TARGET_EXPR) - /* We're disconnecting the initializer from its target, - don't create a temporary. */ - arg = TARGET_EXPR_INITIAL (arg); tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg)); arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t); CALL_EXPR_ARG (function, i) = arg; diff -uprN gcc-11.1.0.orig/gcc/cp/cp-gimplify.c gcc-11.1.0/gcc/cp/cp-gimplify.c --- gcc-11.1.0.orig/gcc/cp/cp-gimplify.c 2021-04-27 03:00:13.000000000 -0700 +++ gcc-11.1.0/gcc/cp/cp-gimplify.c 2021-06-23 21:18:22.342622354 -0700 @@ -320,10 +320,6 @@ simple_empty_class_p (tree type, tree op { if (TREE_CODE (op) == COMPOUND_EXPR) return simple_empty_class_p (type, TREE_OPERAND (op, 1), code); - if (SIMPLE_TARGET_EXPR_P (op) - && 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))) @@ -473,11 +469,6 @@ cp_gimplify_expr (tree *expr_p, gimple_s else if (simple_empty_class_p (TREE_TYPE (op0), op1, code)) { - while (TREE_CODE (op1) == TARGET_EXPR) - /* We're disconnecting the initializer from its target, - don't create a temporary. */ - op1 = TARGET_EXPR_INITIAL (op1); - /* Remove any copies of empty classes. Also drop volatile variables on the RHS to avoid infinite recursion from gimplify_expr trying to load the value. */ @@ -492,9 +483,6 @@ cp_gimplify_expr (tree *expr_p, gimple_s gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_gimple_lvalue, fb_lvalue); *expr_p = TREE_OPERAND (*expr_p, 0); - if (code == RETURN_EXPR && REFERENCE_CLASS_P (*expr_p)) - /* Avoid 'return *;' */ - *expr_p = TREE_OPERAND (*expr_p, 0); } /* P0145 says that the RHS is sequenced before the LHS. gimplify_modify_expr gimplifies the RHS before the LHS, but that @@ -674,6 +662,7 @@ cp_gimplify_expr (tree *expr_p, gimple_s || TREE_CODE (TREE_OPERAND (*expr_p, 0)) == MODIFY_EXPR)) { expr_p = &TREE_OPERAND (*expr_p, 0); + code = TREE_CODE (*expr_p); /* Avoid going through the INIT_EXPR case, which can degrade INIT_EXPRs into AGGR_INIT_EXPRs. */ goto modify_expr_case; diff -uprN gcc-11.1.0.orig/gcc/cp/cp-tree.h gcc-11.1.0/gcc/cp/cp-tree.h --- gcc-11.1.0.orig/gcc/cp/cp-tree.h 2021-04-27 03:00:13.000000000 -0700 +++ gcc-11.1.0/gcc/cp/cp-tree.h 2021-06-23 21:16:51.163744585 -0700 @@ -5225,7 +5225,6 @@ more_aggr_init_expr_args_p (const aggr_i the initializer has void type, it's doing something more complicated. */ #define SIMPLE_TARGET_EXPR_P(NODE) \ (TREE_CODE (NODE) == TARGET_EXPR \ - && TARGET_EXPR_INITIAL (NODE) \ && !VOID_TYPE_P (TREE_TYPE (TARGET_EXPR_INITIAL (NODE)))) /* True if EXPR expresses direct-initialization of a TYPE. */ diff -uprN gcc-11.1.0.orig/gcc/testsuite/g++.dg/abi/empty30.C gcc-11.1.0/gcc/testsuite/g++.dg/abi/empty30.C --- gcc-11.1.0.orig/gcc/testsuite/g++.dg/abi/empty30.C 2021-04-27 03:00:13.000000000 -0700 +++ gcc-11.1.0/gcc/testsuite/g++.dg/abi/empty30.C 1969-12-31 16:00:00.000000000 -0800 @@ -1,14 +0,0 @@ -// PR c++/94175 -// { dg-do link } - -struct A {}; -extern A a; - -int i; -__attribute ((noinline, noclone)) -void f(A) { ++i; } - -int main() -{ - f(a); -}