The IDE copies file to another directory for compilation. It ignores preprocessor directives when doing that. So, SoftwareSerial.h (and SoftwareSerial.cpp) get copied, and added to the list of files to be compiled.
When the compiler compiles your sketch, it sees that SoftwareSerial is not actually needed, and the linker doesn't care whether SoftwareSerial compiled, or not, since it isn't planning to link anything from SoftwareSerial.o into the hex file.
So, no, it is not a compiler bug. It is an IDE feature.
If it were only that simple and actually worked that way.
In reality what happens is that the IDE tries to be "smart" and make things easier for the user by
not requiring the user to write valid/correct/proper C/C++ code.
In order to do this, it has to correct the users code for things like missing function prototypes
and forward variable references.
(That is why it must make a copy of your code into a temporary working area)
In order to do that, it goes in and tries to analyze your code to be able to create prototypes for the functions
and pull in the libraries "it thinks" the code uses and declare references for certain known objects.
And there is where the problem is.
The IDE is simply not smart enough to pull that off.
(BTW, that is a very difficult thing to do properly)
The code that does the analyzing is too simple and doesn't understand even some simple things
like conditional compilation.
As a result it will try to pull in code that is no used
and then depend on the linker to remove it later.
In this case, with the SoftSerial code, the linker cannot remove the code and
the code will be pulled in even though the user code is not referencing or using any of it.
This is because the SoftSerial code uses interrupts and has an ISR routine.
The way the code is written, declared ISR routines will always be pulled in, and because of that other SoftSerial routines
are pulled in, and then because of those, most if not all the SoftSerial code and data variables
will be pulled in.
You can see this if you use avr-objdump to create a .lss file and then look at what code is actually
included into the final linked .elf file that will be used to create the final .hex image which
is what will be uploaded to the AVR.
This is a great example of how the current Arduino build methodology simply doesn't work very well.
There are some simple things that could be done to avoid things like this but so far the Arduino Team
seems very unwilling to address things like this.
If you look at the .lss file you will also see the HardwarSerial code and data being pulled.
Similar thing going on there as well. It is part of the core code and since it has ISRs it
ends up getting pulled in.
This is all done because of combination of the build methodology and the way the code is written/declared/used.
There are some ways to fix this but it takes modifications to the actual library code and to the IDE
so it's not really something than an average Arduino user will be able to fix.
So from my point of view, I see this as a well intended "feature" that kind of sort of works,
but in reality creates many other subtle hard to work around issues.