9 Declarations [dcl.dcl]

9.2 Specifiers [dcl.spec]

9.2.2 Storage class specifiers [dcl.stc]

The storage class specifiers are
storage-class-specifier:
static
thread_local
extern
mutable
At most one storage-class-specifier shall appear in a given decl-specifier-seq, except that thread_local may appear with static or extern.
If thread_local appears in any declaration of a variable it shall be present in all declarations of that entity.
If a storage-class-specifier appears in a decl-specifier-seq, there can be no typedef specifier in the same decl-specifier-seq and the init-declarator-list or member-declarator-list of the declaration shall not be empty (except for an anonymous union declared in a namespace scope ([class.union.anon])).
The storage-class-specifier applies to the name declared by each init-declarator in the list and not to any names declared by other specifiers.
[Note 1: 
See [temp.expl.spec] and [temp.explicit] for restrictions in explicit specializations and explicit instantiations, respectively.
— end note]
[Note 2: 
A variable declared without a storage-class-specifier at block scope or declared as a function parameter has automatic storage duration by default.
— end note]
The thread_local specifier indicates that the named entity has thread storage duration ([basic.stc.thread]).
It shall be applied only to the declaration of a variable of namespace or block scope, to a structured binding declaration ([dcl.struct.bind]), or to the declaration of a static data member.
When thread_local is applied to a variable of block scope the storage-class-specifier static is implied if no other storage-class-specifier appears in the decl-specifier-seq.
The static specifier shall be applied only to the declaration of a variable or function, to a structured binding declaration ([dcl.struct.bind]), or to the declaration of an anonymous union ([class.union.anon]).
There can be no static function declarations within a block, nor any static function parameters.
A static specifier used in the declaration of a variable declares the variable to have static storage duration ([basic.stc.static]), unless accompanied by the thread_local specifier, which declares the variable to have thread storage duration ([basic.stc.thread]).
A static specifier can be used in declarations of class members; [class.static] describes its effect.
For the linkage of a name declared with a static specifier, see [basic.link].
The extern specifier shall be applied only to the declaration of a variable or function.
The extern specifier shall not be used in the declaration of a class member or function parameter.
For the linkage of a name declared with an extern specifier, see [basic.link].
[Note 3: 
The extern keyword can also be used in explicit-instantiations and linkage-specifications, but it is not a storage-class-specifier in such contexts.
— end note]
All declarations for a given entity shall give its name the same linkage.
[Note 4: 
The linkage given by some declarations is affected by previous declarations.
Overloads are distinct entities.
— end note]
[Example 1: static char* f(); // f() has internal linkage char* f() // f() still has internal linkage { /* ... */ } char* g(); // g() has external linkage static char* g() // error: inconsistent linkage { /* ... */ } void h(); inline void h(); // external linkage inline void l(); void l(); // external linkage inline void m(); extern void m(); // external linkage static void n(); inline void n(); // internal linkage static int a; // a has internal linkage int a; // error: two definitions static int b; // b has internal linkage extern int b; // b still has internal linkage int c; // c has external linkage static int c; // error: inconsistent linkage extern int d; // d has external linkage static int d; // error: inconsistent linkage — end example]
The name of a declared but undefined class can be used in an extern declaration.
Such a declaration can only be used in ways that do not require a complete class type.
[Example 2: struct S; extern S a; extern S f(); extern void g(S); void h() { g(a); // error: S is incomplete f(); // error: S is incomplete } — end example]
The mutable specifier shall appear only in the declaration of a non-static data member ([class.mem]) whose type is neither const-qualified nor a reference type.
[Example 3: class X { mutable const int* p; // OK mutable int* const q; // error }; — end example]
[Note 5: 
The mutable specifier on a class data member nullifies a const specifier applied to the containing class object and permits modification of the mutable class member even though the rest of the object is const ([basic.type.qualifier], [dcl.type.cv]).
— end note]