Another approach is to make use of a numbers table (or create your own on the fly if you don't already have one). Assuming you can't ever supply more than 255 doses:
DECLARE @Doses table
(
RowID int IDENTITY(1,1),
DateShipped date,
RemainingDoses tinyint,
RXDays tinyint
);
INSERT @Doses(DateShipped, RemainingDoses, RXDays)
VALUES('20190605',2,30),('20190704',3,24);
-- pseudo Numbers table
DECLARE @num table(n tinyint);
INSERT @num(n) SELECT TOP (256)
row_number() OVER (ORDER BY (SELECT NULL)) - 1
FROM sys.all_columns;
SELECT d.RowID, d.DateShipped, d.RemainingDoses, d.RXDays,
SubsequentShipdate = DATEADD(DAY, n.n*d.RXDays, d.DateShipped)
FROM @Doses AS d
INNER JOIN @num AS n
ON n.n <= d.RemainingDoses
ORDER BY d.RowID, SubsequentShipdate;
Results:

If you only want the "next" dates and not include the original row, just add:
AND n.n > 0
Or, don't include 0 in the numbers table (though it can be useful):
INSERT @num(n) SELECT TOP (255)
row_number() OVER (ORDER BY (SELECT NULL))