C++ inline is totally different to C inline.
#include <iostream>
extern inline int i[];
int i [5];
struct c {
  int function (){return 1;} // implicitly inline
  static inline int j = 3; // explicitly inline
  static int k; // without inline, a static member has to be defined out of line
  static int f (){return 1;} // but a static method does not // implicitly inline
};
extern inline int b;
int b=3;
int c::k = 3; // when a static member is defined out of line it cannot have a static
              // specifier and if it doesn't have an `inline` specifier in the
              // declaration or on the definition then it is not inline and always
              // emits a strong global symbol in the translation unit
int main() {
  c j;
  std::cout << i;
}
inline on its own affects the compiler, assembler and the linker. It is a directive to the compiler saying only emit a symbol for this function/data if it's used in the translation unit, and if it is, then like class methods, tell the assembler to store them in the section .section .text.c::function(),"axG",@progbits,c::function(),comdat or .section .bss.i,"awG",@nobits,i,comdat for unitialised data or .section .data.b,"awG",@progbits,b,comdat for initialised data. Template instantiations also go in their own comdat groups.
This follows .section name, "flags"MG, @type, entsize, GroupName[, linkage]. For instance, the section name is .text.c::function(). axG means the section is allocatable, executable and in a group i.e. a group name will be specified (and there is no M flag so no entsize will be specified); @progbits means the section contains data and isn't blank; c::function() is the group name and the group has comdat linkage meaning that in all object files, all sections encountered with this group name tagged with comdat will be removed from the final executable except for 1 i.e. the compiler makes sure that there is only one definition in the translation unit and then tells the assembler to put it in its own group in the object file (1 section in 1 group) and then the linker will make sure that if any object files have a group with the same name, then only include one in the final .exe. The difference between inline and not using inline is now visible to the assembler and as a result the linker, because it's not stored in the regular .data or .text etc by the assembler due to their directives. Only inline symbols with external linkage are given external comdat linkage like this -- static linkage (local) symbols do not need to go in comdat groups.
inline on a non-static method declaration in a class makes the method inline if it is defined out-of-line, this will prevent the method being emitted in the translation unit if it is not referenced in the translation unit. The same effect is achieved by putting inline on the out-of-line definition. When a method is defined out-of-line without an inline specifier and the declaration in the class is not inline then it will emit a symbol for the method in the translation unit at all times because it will have external linkage rather than external comdat linkage. If the method is defined in the class then it is implicitly inline, which gives it external comdat linkage rather than external linkage.
static inline on a member in a class (as opposed to method) makes it a static member (which does not refer to its linkage -- it has the linkage of its class which may be extern). static inline also allows static members of the class to be defined inside the class instead of needing to be declared in the class and then defined out-of-line (without static in the definition, which wasn't allowed without -fpermissive). *static inline* also makes the members inline and not static inline -- inline means that the definition is only emitted if it is referenced in the translation unit. Previously you had to specify inline on the out-of-line definition to make the member inline.
Seeing as static methods can be defined in the class, static inline has no effect on the static method defined in the class, which always has external linkage, is a static method and is inline. If it is defined out of line then inline must be used to make it inline (i.e. to give to external comdat linkage rather than just external linkage), and static still can't be used.
static inline at file scope only affects the compiler. It means to the compiler: only emit a symbol for this function/data if it's used in the translation unit and do so as a regular static symbol (store in.text /.data without .globl directive). To the assembler there is now no difference between static and static inline. Like the other forms of inline, it cannot be used on a class, which is a type, but can be used on an object of the type of that class. This form of static inline also cannot be used on members or methods of a function, where it will always be treated inline as the static means something else in a class (it means that the class is acting as a scope rather than it being a member of or method to be used on an object).
extern inline is a declaration that means you must define this symbol in the translation unit if it is referenced or throw compiler error; if it's defined then treat it as a regular inline and to the assembler and linker there will be no difference between extern inline and inline, so this is a compiler guard only.
extern inline int i[];
extern int i[]; //allowed repetition of declaration with incomplete type, inherits inline property
extern int i[5]; //declaration now has complete type
extern int i[5]; //allowed redeclaration if it is the same complete type or has not yet been completed
extern int i[6]; //error, redeclaration with different complete type
int i[5]; //definition, must have complete type and same complete type as the declaration if there is a declaration with a complete type
The whole of the above without the error line collapses to inline int i[5]. Obviously if you did extern inline int i[] = {5}; then extern would be ignored due to the explicit definition through assignment.
I think the reason that static is not allowed on a static out-of-line definition without -fpermissive is because it implies that the static refers to static linkage, because it's not immediately obvious to the programmer that it is a member of a class or whether that class has , where the static means something different. -fpermissive ignores the static specifier on the out-of-line definition and it means nothing. In the case of a simple integer, k can't be defined out of a namespace, if c were a namespace, but if k were a function, then there would be no way of visibly telling from the line of code whether it is an out of line definition of a function in a namespace with static linkage, or an out-of-line definition of a static member with external linkage, and may give the wrong impression to the programmer / reader of the code.
For local classes, inline on a member / method will result in a compiler error and members and methods have no linkage.
For inline on a namespace, see this and this