BUG/API: concat with empty DataFrames or all-NA columns
- [ ] closes #xxxx
- [ ] tests added / passed
- [ ] Ensure all linting tests pass, see [here](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit) for how to run them
- [ ] whatsnew entry

This is in the grey area between a bugfix and an API change.  Towards the bugfix side, it fixes some truly strange behavior:

1) Concatenating ignores the dtypes of all-NaN columns (see test_append_dtypes)
```
import numpy as np
import pandas as pd
import pandas._testing as tm

df1 = pd.DataFrame({"bar": pd.Timestamp("20130101")}, index=range(1))
df2 = pd.DataFrame({"bar": np.nan}, index=range(1, 2))
df3 = df2.astype(object)

result = df1.append(df2)
expected = pd.DataFrame(
    {"bar": pd.Series([pd.Timestamp("20130101"), np.nan], dtype="M8[ns]")}
)
tm.assert_frame_equal(result, expected)

result2 = df1.append(df3)
tm.assert_frame_equal(result2, expected)
```

2) Concatenating _sometimes_ ignores the dtype on empty (see test_join_append_timedeltas)

```
df = pd.DataFrame(columns=["d", "t"])  # <- object dtype
df2 = pd.DataFrame({"d": [pd.Timestamp(2013, 11, 5, 5, 56)], "t": [pd.Timedelta(seconds=22500)]})

result = df.append(df2, ignore_index=True)  # <- *not* object dtype
assert (result.dtypes == df2.dtypes).all()
```

The change in indexing code/tests is the least-invasive I could make it.

cc @jorisvandenbossche, this moves us towards having less values-dependent behavior, also makes the BM behavior more like the AM behavior in several affected cases.

Lots of cleanup becomes available after this, leaving for follow-up.
