Only a function created with a function declaration is hoisted. The function in return function fn2(){};
is created with a (named) function expression so is not hoisted.
How a function is evaluated is dependent on context. Any function within a statement (such as a return statement) is parsed as a function expression. Another example is the use of parentheses in IIFEs: the parentheses act as a grouping operator, ensuring that the contents of the parentheses are evaluated as an expression.
Lots of information about this can be found in Kangax's excellent article: