Allow const/let/var above declaration if not used.

(this is a re-opened PR #1658 against `master` instead of the removed `2.x` branch)

Ref gh-1462

@valueof I made it work for `const` but I have no idea how to make it work for `let`. From what I see, `var` & `const` are handled by one data structure (though with weirdnesses like `var` being written as `unused` when not used and `const` being just `const` in such a case just with a special `unused` property written in a different structure that is ignored in the `var` case...) but `let` is handled in a completely different way.

I spent some time looking at the code but I cannot figure out what's exactly going on here... Could you help me make it work for `let` as well?
@valueof first of all, you're not stupid. "Temporal Dead Zone" is a term that originates in TC39 for these semantics, not really google-able. It describes the "time" of execution from the point a block (scope) begins and the point in which a const or let binding is actually declared. This was designed to fail fast to help developers avoid writing insane broken code. Here is a trivial example of code that will throw a TDZ exception: 


```js
{
  // the block has begun, we're in a new block scope. the TDZ for the "a" binding has begun

  var f = function() {
    // 2. because this is evaluated before "a" is actually declared, it's going to throw an exception 
    // that will tell the user that "a" is not yet defined.
    console.log(a); 
  };

  f(); // 1. this is called and results evaluated before the next line... 
  let a = 1; 
  // The "a" binding is now safe, but we never got here because f() killed us :(
  // that's ok, because we can fix this bug and celebrate the win!
}