struct Base { Base(); int i; char c; }; template <typename BaseT> struct actor : public BaseT { actor(BaseT const& base); char c; }; template <typename BaseT> actor<BaseT>::actor(BaseT const& base) : BaseT(base) {} actor<Base> foo(const Base c) { return actor<Base>(c); } with -O2 we inline the constructor and get actor<Base> foo(Base) D.2099 (const struct Base c) { struct actor D.2133; struct actor D.2134; <bb 2>: D.2133.D.2111 = c; D.2134 = D.2133; return D.2134; } The assignment D.2133.D.2111 = c; has on the LHS a size of 40 (from the FIELD_DECL) and on the RHS a size of 64, from the decl. In the un-inlined constructor we had the bogus actor<BaseT>::actor(const BaseT&) [with BaseT = Base] D.2105 (struct actor * const this, const struct Base & base) { <bb 2>: this_1(D)->D.2111 = *base_2(D); return; } with the same issue (size 40 on the lhs, size 64 on the rhs). "Size" in term of what the FIELD_DECL DECL_SIZE says for the component-refs, which is according to people what is relevant - not the type size. Likewise for the RHS the DECL_SIZE (which is equal to TYPE_SIZE). For less contrived examples the FE generates a memcpy to carefully _not_ overwrite padding that may be used in tail packing. Eventually from the above you can construct a wrong-code testcase if expansion chooses the wrong size for the expansion of the assignment.
Your comment to the patch that removed LANG_HOOKS_EXPR_SIZE suggests that this isn't a problem anymore: http://gcc.gnu.org/ml/gcc-patches/2009-08/msg01593.html
We still have these constructs and expand still properly deals with them (it uses the size of the LHS). I'm not sure what's the best thing to do about this bug. Eventually better documenting what sizes in an assignment are really relevant. The FE now indeed emits memcpy whenever there is not a DECL or FIELD_DECL on the LHS that specifies sizes, like for void bar (Base *p, Base *q) { *p = *q; } ;; Function void bar(Base*, Base*) (null) ;; enabled by -tree-original <<cleanup_point <<< Unknown tree: expr_stmt (void) (struct Base *) __builtin_memcpy (NON_LVALUE_EXPR <p>, (const struct Base &) (const struct Base *) NON_LVALUE_EXPR <q>, 5) >>> >>; So the langhook was no longer necessary.
If this ever gets fixed, we can remove a test in SRA as in: http://gcc.gnu.org/ml/gcc-patches/2012-03/msg01356.html