As analyzed by Nathan and Paolo, the problem here is that the test conversion in check_default_arg is changing the expression, but then we discard the result. Excessive sharing of CONSTRUCTORs is an ongoing issue, due to past decisions motivated by memory savings. For the time being, we can specifically unshare the default argument if it is an initializer-list, since that's the problematic case.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit f905470ca5ccda134972fdab07f7ed9a0380bf25 Author: Jason Merrill <ja...@redhat.com> Date: Tue Mar 13 19:34:54 2018 -0400 PR c++/82336 - link error with list-init default argument. * decl.c (check_default_argument): Unshare an initializer list. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index afd04cea630..6c113f25a3d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -12661,7 +12661,9 @@ check_default_argument (tree decl, tree arg, tsubst_flags_t complain) A default argument expression is implicitly converted to the parameter type. */ ++cp_unevaluated_operand; - perform_implicit_conversion_flags (decl_type, arg, complain, + /* Avoid digest_init clobbering the initializer. */ + tree carg = BRACE_ENCLOSED_INITIALIZER_P (arg) ? unshare_expr (arg): arg; + perform_implicit_conversion_flags (decl_type, carg, complain, LOOKUP_IMPLICIT); --cp_unevaluated_operand; diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-defarg2.C b/gcc/testsuite/g++.dg/cpp0x/initlist-defarg2.C new file mode 100644 index 00000000000..65240355fc3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-defarg2.C @@ -0,0 +1,8 @@ +// PR c++/82336 +// { dg-do link { target c++11 } } + +struct foo { int x = 5; }; +struct bar : foo { bar() = default; }; +struct baz { bar x; }; +void qux(baz = {}){} +int main() { qux(); }