summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--js/src/frontend/Parser.cpp26
-rw-r--r--js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js5
-rw-r--r--js/src/vm/Scope.cpp8
-rw-r--r--js/src/vm/Scope.h11
4 files changed, 41 insertions, 9 deletions
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index 7e43bc3b5..2e13910df 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1211,6 +1211,25 @@ Parser<ParseHandler>::tryDeclareVarForAnnexBLexicalFunction(HandlePropertyName n
if (!tryDeclareVar(name, DeclarationKind::VarForAnnexBLexicalFunction, &redeclaredKind))
return false;
+ if (!redeclaredKind && pc->isFunctionBox()) {
+ ParseContext::Scope& funScope = pc->functionScope();
+ ParseContext::Scope& varScope = pc->varScope();
+ if (&funScope != &varScope) {
+ // Annex B.3.3.1 disallows redeclaring parameter names. In the
+ // presence of parameter expressions, parameter names are on the
+ // function scope, which encloses the var scope. This means
+ // tryDeclareVar call above would not catch this case, so test it
+ // manually.
+ if (AddDeclaredNamePtr p = funScope.lookupDeclaredNameForAdd(name)) {
+ DeclarationKind declaredKind = p->value()->kind();
+ if (DeclarationKindIsParameter(declaredKind))
+ redeclaredKind = Some(declaredKind);
+ else
+ MOZ_ASSERT(FunctionScope::isSpecialName(context, name));
+ }
+ }
+ }
+
if (redeclaredKind) {
// If an early error would have occurred, undo all the
// VarForAnnexBLexicalFunction declarations.
@@ -1751,11 +1770,8 @@ Parser<FullParseHandler>::newFunctionScopeData(ParseContext::Scope& scope, bool
case BindingKind::Var:
// The only vars in the function scope when there are parameter
// exprs, which induces a separate var environment, should be the
- // special internal bindings.
- MOZ_ASSERT_IF(hasParameterExprs,
- bi.name() == context->names().arguments ||
- bi.name() == context->names().dotThis ||
- bi.name() == context->names().dotGenerator);
+ // special bindings.
+ MOZ_ASSERT_IF(hasParameterExprs, FunctionScope::isSpecialName(context, bi.name()));
if (!vars.append(binding))
return Nothing();
break;
diff --git a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js b/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js
index f0adedf7d..ae7fbe879 100644
--- a/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js
+++ b/js/src/tests/ecma_6/LexicalEnvironment/block-scoped-functions-annex-b-parameter.js
@@ -11,6 +11,11 @@
assertEq(f, 123);
}(123));
+(function(f = 123) {
+ assertEq(f, 123);
+ { function f() { } }
+ assertEq(f, 123);
+}());
if (typeof reportCompare === "function")
reportCompare(true, true);
diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp
index a71c03695..0f80d7b69 100644
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -669,6 +669,14 @@ FunctionScope::script() const
return canonicalFunction()->nonLazyScript();
}
+/* static */ bool
+FunctionScope::isSpecialName(ExclusiveContext* cx, JSAtom* name)
+{
+ return name == cx->names().arguments ||
+ name == cx->names().dotThis ||
+ name == cx->names().dotGenerator;
+}
+
/* static */ Shape*
FunctionScope::getEmptyEnvironmentShape(ExclusiveContext* cx, bool hasParameterExprs)
{
diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h
index 1d04fd9f6..4a4ae8090 100644
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -446,10 +446,11 @@ Scope::is<LexicalScope>() const
}
//
-// Scope corresponding to a function. Holds formal parameter names and, if the
-// function parameters contain no expressions that might possibly be
-// evaluated, the function's var bindings. For example, in these functions,
-// the FunctionScope will store a/b/c bindings but not d/e/f bindings:
+// Scope corresponding to a function. Holds formal parameter names, special
+// internal names (see FunctionScope::isSpecialName), and, if the function
+// parameters contain no expressions that might possibly be evaluated, the
+// function's var bindings. For example, in these functions, the FunctionScope
+// will store a/b/c bindings but not d/e/f bindings:
//
// function f1(a, b) {
// var cÍž
@@ -562,6 +563,8 @@ class FunctionScope : public Scope
return data().nonPositionalFormalStart;
}
+ static bool isSpecialName(ExclusiveContext* cx, JSAtom* name);
+
static Shape* getEmptyEnvironmentShape(ExclusiveContext* cx, bool hasParameterExprs);
};