See Compiler Explorer as an example. When value-initializing a type with an explicitly defaulted constructor, Clang generates code that goes out of its way to not zero the padding bits, which generates more code than expected. Building with -std=c++20 or removing the explicit constructor just zeroes the entire struct, as expected. gcc zeroes the entire struct even with -std=c++17. How come Clang doesn’t?
The C++17 vs. C++20 difference is because the rules for aggregates changed; the C++20 version is calling the default constructor (CXXConstructExpr), the C++17 version is using aggregate initialization (an InitListExpr). You can see this with “-Xclang -ast-dump”.
Given that, it’s easy to conclude there’s an optimization which exists on the CXXConstructExpr codepath, but not on the InitListExpr codepath. (And as usual, the answer to “why isn’t optimization X implemented” is “nobody implemented it”.)
Oh, wait, I didn’t notice the difference between the two C++17 examples. I think the check at https://github.com/llvm/llvm-project/blob/44d17cd739c5ea3d085509c46e149b7f4359f36c/clang/lib/CodeGen/CGExprAgg.cpp#L2007 is causing that; probably hasUserDeclaredConstructor() is not the right condition.
Ah yeah, I think that should be conditioned on a user-provided constructor (i.e. not = default) as opposed to a user-declared one.