Make a calendar table (do this one time only), this one courtesy of sqlskull.com:
DECLARE @Year INT = '2000';
DECLARE @YearCnt INT = 50 ;
DECLARE @StartDate DATE = DATEFROMPARTS(@Year, 1, 1)
DECLARE @EndDate DATE = DATEADD(DAY, -1, DATEADD(YEAR, @YearCnt, @StartDate));
;WITH Cal(n) AS
(
SELECT 0 UNION ALL SELECT n + 1 FROM Cal
WHERE n < DATEDIFF(DAY, @StartDate, @EndDate)
),
FnlDt(d) AS
(
SELECT DATEADD(DAY, n, @StartDate), n FROM Cal
),
FinalCte AS
(
SELECT
[D] = CONVERT(DATE,d),
[Dy] = DATEPART(DAY, d),
[Mo] = DATENAME(MONTH, d),
[Yr] = DATEPART(YEAR, d),
[DN] = DATENAME(WEEKDAY, d),
N
FROM FnlDt
)
SELECT *
INTO tally
FROM finalCte
ORDER BY [Date]
OPTION (MAXRECURSION 0);
Now you have a dates and numbers table you can use forever more, like this:
SELECT *
FROM
(SELECT
cust_id,
min(bill_date) minbill,
max(bill_date) maxbill
FROM t
) r
INNER JOIN tally x ON x.Dy = DAY(minbill) AND x.d BETWEEN r.minbill AND r.maxbill
LEFT JOIN t ON x.d = t.bill_date and r.cust_id = t.cust_id
The grouping query inner joined to the tally table is your cross join (it can't be a cross because it does have some predicate, namely that the tally rows be between min and max). This will cause each grouped-per-customer row to multiply up to the number of dates in the tally between the min and max - it gives you a cross join of every customer id joined to every date between min and max.
Then you just need to connect it back to the cust data table using a left join to get either the dates that do have data or dates that don't (and leave the tally date in for those days that don't have any customer data - convert the null to a 0)