Your code does not work because even with drop = FALSE the missing categories are still not present in ..count.. and ..x... This can be seen by plotting ..count.. and ..x...
library("tidyverse")
df <- data.frame(
location = c(rep("in", 231), rep("out", 83)),
status = c(rep("normal", 73), rep("mild", 42), rep("moderate", 20), rep("fever", 4),
rep("normal", 70), rep("mild", 41), rep("moderate", 62), rep("fever", 2)))
df$status <- factor(df$status, levels = c("normal", "mild", "moderate", "severe", "fever"))
Plot ..count..
df %>%
ggplot(aes(x = status,
y = ..count..,
fill = location)) +
geom_bar(position = "dodge") +
scale_x_discrete(drop=F)

The missing categories are not present in ..count.. which we can infer from the fact that for normal only one value shows up, i.e. ..count.. is the vector
..count.. <- c(143, 64, 19, 20, 62, 4, 2)
Plot ..x..
df %>%
ggplot(aes(x = status,
y = ..x..,
fill = location)) +
geom_bar(position = "dodge") +
scale_x_discrete(drop=F)

As with ..count.. the missing categories are not present in ..x.. i.e. ..x.. is the vector
..x.. <- c(1, 2, 2, 3, 3, 5, 5)
Why the code does not work
As a first step I compute tapply(..count.., ..x.., sum) which gives us a vector of length 4 (total counts for non-missing status categories):
tapply(..count.., ..x.., sum)
#> 1 2 3 5
#> 143 83 82 6
Now, extracting the elements via [..x..] results in
tapply(..count.., ..x.., sum)[..x..]
#> 1 2 2 3 3 <NA> <NA>
#> 143 83 83 82 82 NA NA
or
..count.. / tapply(..count.., ..x.., sum)[..x..]
#> 1 2 2 3 3 <NA> <NA>
#> 1.0000 0.7711 0.2289 0.2439 0.7561 NA NA
Hence your code results in two missings for the last two categories, which explains the warning Removed 2 rows containing missing values (geom_bar). The reason is that with ..x.. <- c(1, 2, 2, 3, 3, 5, 5) we are trying to extract two times the 5th element from the length 4 vector tapply(..count.., ..x.., sum) and therefore get NAs back.
In case of drop=TRUE everything works fine because in that case ..x.. <- c(1, 2, 2, 3, 3, 4, 4) while ..count.. is the same.
Solution
The issue can be solved by converting ..x.. to a character vector. In that case we extract elements by names:
library("tidyverse")
df <- data.frame(
location = c(rep("in", 231), rep("out", 83)),
status = c(rep("normal", 73), rep("mild", 42), rep("moderate", 20), rep("fever", 4),
rep("normal", 70), rep("mild", 41), rep("moderate", 62), rep("fever", 2)))
df$status <- factor(df$status, levels = c("normal", "mild", "moderate", "severe", "fever"))
# Convert ..x.. to character
df %>%
ggplot(aes(x = status,
y = ..count.. / tapply(..count.., ..x.., sum)[as.character(..x..)],
fill = location)) +
geom_bar(position = "dodge") +
scale_x_discrete(drop=F)

Created on 2020-03-23 by the reprex package (v0.3.0)