For this block scope declaration
extern int a;
the compiler searches a previous declaration of the name a
in the global namespace that to determine whether it has external or internal linkage. If the compiler does not find the previous declaration it thinks that the variable a
refers to a variable defined in the global namespace with external linkage.
And indeed there is a definition of the variable in the global namespace
int a=20;
So the two declarations refer to the same object defined in the global namespace.
From the C++ 17 Standard (6.5 Program and linkage)
2 A name is said to have linkage when it might denote the same object,
reference, function, type, template, namespace or value as a name
introduced by a declaration in another scope:
and
6 The name of a function declared in block scope and the name of a
variable declared by a block scope extern declaration have linkage. If
there is a visible declaration of an entity with linkage having the
same name and type, ignoring entities declared outside the innermost
enclosing namespace scope, the block scope declaration declares that
same entity and receives the linkage of the previous declaration. If
there is more than one such matching entity, the program is
ill-formed. Otherwise, if no matching entity is found, the block scope
entity receives external linkage. If, within a translation unit, the
same entity is declared with both internal and external linkage, the
program is ill-formed.
That is a declaration in a block scope with the storage class specifier extern
does not define a new object. It refers to an object with the same name defined in the enclosing namespace with an internal or external linkage.