Okay, so after reading through VivienG's link, I think I've understood the exact reasoning behind this error message. It's confusing and misleading (at least to me; it shouldn't happen if you've got just one translation unit), yet it is possible to explain:
- Assuming the compiler doesn't want to actually inline the code, it has to know where to put that function, especially when it's used in multiple translation units. 
- Classic approach is to create multiple copies, one for each translation unit (or at least for those units where it's used). 
- This may cause problems, e.g. when trying to do some function pointer comparisons (still leaves the question why you'd to that though). 
To counter this (and other issues I possibly didn't list here), they've thought of some actually quite neat (although - as mentioned - in my opinion misleading) solution:
You declare the function as inline the way you know, but at the same time you tell the compiler where to put the non-inline version with the extern keyword.
So in your example, you'd keep your function as-is and put it in a header file (so it's known where it's going to be used):
inline int foo(void)
{
     return  10 + 3;
}
In addition, to tell the compiler where to place the non-inlined version, you'll have to add one more "forward" declaration in one translation unit:
extern inline int foo(void);
So the whole concept is essentially reversed when compared to classic functions: Put the implementation in the header and then a short declaration in just one file.
As mentioned already, while using the -O3 parameter, all code marked with inline is actually inlined, which won't cause the issue to happen.