(1) {gcc,clang} -fuse-ld=bfd -pie -fPIE -nostdlib a.c => .interp created
(2) {gcc,clang} -fuse-ld=lld -pie -fPIE -nostdlib a.c => .interp not created
(3) {gcc,clang} -fuse-ld=lld -pie -fPIE -nostdlib a.c a.so => .interp created
The inconsistency of (2) is due to the condition !Config->SharedFiles.empty().
To make lld behave more like ld.bfd, we could change the condition to:
Config->HasDynSymTab && !Config->DynamicLinker.empty() && Script->needsInterpSection();
However, that would bring another inconsistency as can be observed with:
(4) {gcc,clang} -fuse-ld=bfd -no-pie -nostdlib a.c => .interp not created
So instead, use !Config->DynamicLinker.empty() && Script->needsInterpSection(),
which is both simple and consistent in these cases.
The inconsistency likely originated from ld.bfd and gold's choice to
have a default --dynamic-linker. Their condition to create .interp is
ANDed with (not -shared). Since lld doesn't have a default
--dynamic-linker, and compiler drivers (gcc/clang) don't pass
--dynamic-linker with -shared, we do not need the condition
Config->Shared. For direct ld users, they are not suppoped to specify
--dynamic-linker for a -shared link.