Strictly speaking C requires that functions be forward declared for the compiler to compile and link them.
In the first example you have not only declared the function but also defined it in the same space.
This is perfectly fine and legal for proper C.
The second example has the function definition after the loop but no declaration before the setup() function.
In order to get the compiler to “see” the bb() function you must declare it before the setup function.
This is valid and will compile.
// any code here
Now the compiler knows that you have a function named bb() defined elsewhere in the file. its prototype ( i.e returning void and taking no parameters) being declared ahead of its actual usage will allow the compiler to compile.
Arduino framework by itself does this job for you behind the scenes. thats why it compiles fine in the Arduino IDE.