Bug 1542406 - Restrict contents of direct eval in fields. r=jorendorff
authorAshley Hauck <khyperia@mozilla.com>
Wed, 24 Apr 2019 18:45:13 +0000
changeset 530008 c66792afc2c28ae0a555c73f4e34b87435f1f7b6
parent 530007 afb947a236befa6eb6f23783405bd9c334aa4129
child 530009 41ac1be62749371f9eefbfd6c3d8ab0747efac8e
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1542406
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1542406 - Restrict contents of direct eval in fields. r=jorendorff Differential Revision: https://phabricator.services.mozilla.com/D27152
js/src/frontend/BinASTParserPerTokenizer.cpp
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SharedContext.cpp
js/src/tests/jstests.list
js/src/vm/Scope.cpp
js/src/vm/Scope.h
--- a/js/src/frontend/BinASTParserPerTokenizer.cpp
+++ b/js/src/frontend/BinASTParserPerTokenizer.cpp
@@ -360,19 +360,22 @@ JS::Result<FunctionNode*> BinASTParserPe
   BINJS_TRY(pc_->declareFunctionArgumentsObject(usedNames_,
                                                 canSkipLazyClosedOverBindings));
   BINJS_TRY(
       pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings));
 
   // Check all our bindings after maybe adding function metavars.
   MOZ_TRY(checkFunctionClosedVars());
 
-  BINJS_TRY_DECL(bindings, NewFunctionScopeData(cx_, pc_->functionScope(),
-                                                /* hasParameterExprs = */ false,
-                                                alloc_, pc_));
+  BINJS_TRY_DECL(
+      bindings,
+      NewFunctionScopeData(cx_, pc_->functionScope(),
+                           /* hasParameterExprs = */ false,
+                           IsFieldInitializer::No,
+                           alloc_, pc_));
 
   funbox->functionScopeBindings().set(*bindings);
 
   if (funbox->function()->isNamedLambda()) {
     BINJS_TRY_DECL(
         recursiveBinding,
         NewLexicalScopeData(cx_, pc_->namedLambdaScope(), alloc_, pc_));
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1111,21 +1111,19 @@ Maybe<EvalScope::Data*> NewEvalScopeData
   return Some(bindings);
 }
 
 Maybe<EvalScope::Data*> ParserBase::newEvalScopeData(
     ParseContext::Scope& scope) {
   return NewEvalScopeData(cx_, scope, alloc_, pc_);
 }
 
-Maybe<FunctionScope::Data*> NewFunctionScopeData(JSContext* cx,
-                                                 ParseContext::Scope& scope,
-                                                 bool hasParameterExprs,
-                                                 LifoAlloc& alloc,
-                                                 ParseContext* pc) {
+Maybe<FunctionScope::Data*> NewFunctionScopeData(
+    JSContext* cx, ParseContext::Scope& scope, bool hasParameterExprs,
+    IsFieldInitializer isFieldInitializer, LifoAlloc& alloc, ParseContext* pc) {
   BindingNameVector positionalFormals(cx);
   BindingNameVector formals(cx);
   BindingNameVector vars(cx);
 
   bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
   bool hasDuplicateParams = pc->functionBox()->hasDuplicateParameters;
 
   // Positional parameter names must be added in order of appearance as they are
@@ -1195,28 +1193,32 @@ Maybe<FunctionScope::Data*> NewFunctionS
       positionalFormals.length() + formals.length() + vars.length();
 
   if (numBindings > 0) {
     bindings = NewEmptyBindingData<FunctionScope>(cx, alloc, numBindings);
     if (!bindings) {
       return Nothing();
     }
 
+    bindings->isFieldInitializer = isFieldInitializer;
+
     // The ordering here is important. See comments in FunctionScope.
     InitializeBindingData(bindings, numBindings, positionalFormals,
                           &FunctionScope::Data::nonPositionalFormalStart,
                           formals, &FunctionScope::Data::varStart, vars);
   }
 
   return Some(bindings);
 }
 
 Maybe<FunctionScope::Data*> ParserBase::newFunctionScopeData(
-    ParseContext::Scope& scope, bool hasParameterExprs) {
-  return NewFunctionScopeData(cx_, scope, hasParameterExprs, alloc_, pc_);
+    ParseContext::Scope& scope, bool hasParameterExprs,
+    IsFieldInitializer isFieldInitializer) {
+  return NewFunctionScopeData(cx_, scope, hasParameterExprs, isFieldInitializer,
+                              alloc_, pc_);
 }
 
 Maybe<VarScope::Data*> NewVarScopeData(JSContext* cx,
                                        ParseContext::Scope& scope,
                                        LifoAlloc& alloc, ParseContext* pc) {
   BindingNameVector vars(cx);
 
   bool allBindingsClosedOver = pc->sc()->allBindingsClosedOver();
@@ -1609,35 +1611,36 @@ bool PerHandlerParser<ParseHandler>::fin
     }
   }
 
   return true;
 }
 
 template <>
 bool PerHandlerParser<FullParseHandler>::finishFunction(
-    bool isStandaloneFunction /* = false */) {
+    bool isStandaloneFunction /* = false */,
+    IsFieldInitializer isFieldInitializer /* = IsFieldInitializer::No */) {
   if (!finishFunctionScopes(isStandaloneFunction)) {
     return false;
   }
 
   FunctionBox* funbox = pc_->functionBox();
   bool hasParameterExprs = funbox->hasParameterExprs;
 
   if (hasParameterExprs) {
     Maybe<VarScope::Data*> bindings = newVarScopeData(pc_->varScope());
     if (!bindings) {
       return false;
     }
     funbox->extraVarScopeBindings().set(*bindings);
   }
 
   {
-    Maybe<FunctionScope::Data*> bindings =
-        newFunctionScopeData(pc_->functionScope(), hasParameterExprs);
+    Maybe<FunctionScope::Data*> bindings = newFunctionScopeData(
+        pc_->functionScope(), hasParameterExprs, isFieldInitializer);
     if (!bindings) {
       return false;
     }
     funbox->functionScopeBindings().set(*bindings);
   }
 
   if (funbox->function()->isNamedLambda() && !isStandaloneFunction) {
     Maybe<LexicalScope::Data*> bindings =
@@ -1648,17 +1651,18 @@ bool PerHandlerParser<FullParseHandler>:
     funbox->namedLambdaBindings().set(*bindings);
   }
 
   return true;
 }
 
 template <>
 bool PerHandlerParser<SyntaxParseHandler>::finishFunction(
-    bool isStandaloneFunction /* = false */) {
+    bool isStandaloneFunction /* = false */,
+    IsFieldInitializer isFieldInitializer /* = IsFieldInitializer::Yes */) {
   // The LazyScript for a lazily parsed function needs to know its set of
   // free variables and inner functions so that when it is fully parsed, we
   // can skip over any already syntax parsed inner functions and still
   // retain correct scope information.
 
   if (!finishFunctionScopes(isStandaloneFunction)) {
     return false;
   }
@@ -7466,17 +7470,18 @@ GeneralParser<ParseHandler, Unit>::field
   LexicalScopeNodeType initializerBody =
       finishLexicalScope(lexicalScope, statementList);
   if (!initializerBody) {
     return null();
   }
 
   handler_.setFunctionBody(funNode, initializerBody);
 
-  if (!finishFunction()) {
+  if (!finishFunction(/* isStandaloneFunction = */ false,
+                      IsFieldInitializer::Yes)) {
     return null();
   }
 
   return funNode;
 }
 
 bool ParserBase::nextTokenContinuesLetDeclaration(TokenKind next) {
   MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Let));
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -428,17 +428,18 @@ class MOZ_STACK_CLASS ParserBase : publi
 
  public:
   mozilla::Maybe<GlobalScope::Data*> newGlobalScopeData(
       ParseContext::Scope& scope);
   mozilla::Maybe<ModuleScope::Data*> newModuleScopeData(
       ParseContext::Scope& scope);
   mozilla::Maybe<EvalScope::Data*> newEvalScopeData(ParseContext::Scope& scope);
   mozilla::Maybe<FunctionScope::Data*> newFunctionScopeData(
-      ParseContext::Scope& scope, bool hasParameterExprs);
+      ParseContext::Scope& scope, bool hasParameterExprs,
+      IsFieldInitializer isFieldInitializer);
   mozilla::Maybe<VarScope::Data*> newVarScopeData(ParseContext::Scope& scope);
   mozilla::Maybe<LexicalScope::Data*> newLexicalScopeData(
       ParseContext::Scope& scope);
 
  protected:
   enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true };
   enum ForInitLocation { InForInit, NotInForInit };
 
@@ -545,17 +546,19 @@ class MOZ_STACK_CLASS PerHandlerParser :
   }
 
   // Required on Scope exit.
   bool propagateFreeNamesAndMarkClosedOverBindings(ParseContext::Scope& scope);
 
   bool finishFunctionScopes(bool isStandaloneFunction);
   LexicalScopeNodeType finishLexicalScope(ParseContext::Scope& scope,
                                           Node body);
-  bool finishFunction(bool isStandaloneFunction = false);
+  bool finishFunction(
+      bool isStandaloneFunction = false,
+      IsFieldInitializer isFieldInitializer = IsFieldInitializer::No);
 
   inline NameNodeType newName(PropertyName* name);
   inline NameNodeType newName(PropertyName* name, TokenPos pos);
 
   NameNodeType newInternalDotName(HandlePropertyName name);
   NameNodeType newThisName();
   NameNodeType newDotGeneratorName();
 
@@ -1879,17 +1882,17 @@ mozilla::Maybe<GlobalScope::Data*> NewGl
     JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc,
     ParseContext* pc);
 mozilla::Maybe<EvalScope::Data*> NewEvalScopeData(JSContext* context,
                                                   ParseContext::Scope& scope,
                                                   LifoAlloc& alloc,
                                                   ParseContext* pc);
 mozilla::Maybe<FunctionScope::Data*> NewFunctionScopeData(
     JSContext* context, ParseContext::Scope& scope, bool hasParameterExprs,
-    LifoAlloc& alloc, ParseContext* pc);
+    IsFieldInitializer isFieldInitializer, LifoAlloc& alloc, ParseContext* pc);
 mozilla::Maybe<VarScope::Data*> NewVarScopeData(JSContext* context,
                                                 ParseContext::Scope& scope,
                                                 LifoAlloc& alloc,
                                                 ParseContext* pc);
 mozilla::Maybe<LexicalScope::Data*> NewLexicalScopeData(
     JSContext* context, ParseContext::Scope& scope, LifoAlloc& alloc,
     ParseContext* pc);
 
--- a/js/src/frontend/SharedContext.cpp
+++ b/js/src/frontend/SharedContext.cpp
@@ -12,23 +12,29 @@
 #include "vm/EnvironmentObject-inl.h"
 
 namespace js {
 namespace frontend {
 
 void SharedContext::computeAllowSyntax(Scope* scope) {
   for (ScopeIter si(scope); si; si++) {
     if (si.kind() == ScopeKind::Function) {
-      JSFunction* fun = si.scope()->as<FunctionScope>().canonicalFunction();
+      FunctionScope* funScope = &si.scope()->as<FunctionScope>();
+      JSFunction* fun = funScope->canonicalFunction();
       if (fun->isArrow()) {
         continue;
       }
       allowNewTarget_ = true;
       allowSuperProperty_ = fun->allowSuperProperty();
       allowSuperCall_ = fun->isDerivedClassConstructor();
+      if (funScope->isFieldInitializer() == IsFieldInitializer::Yes) {
+        allowSuperProperty_ = false;
+        allowSuperCall_ = false;
+        allowArguments_ = false;
+      }
       return;
     }
   }
 }
 
 void SharedContext::computeThisBinding(Scope* scope) {
   for (ScopeIter si(scope); si; si++) {
     if (si.kind() == ScopeKind::Module) {
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -553,51 +553,21 @@ skip script test262/built-ins/RegExp/pro
 # The Intl spec recently changed from canonicalizing locales using RFC 5646 to
 # using UTS 35.  This still needs to be implemented in bug 1522070.  See also
 # <https://github.com/tc39/ecma402/commit/77cd7634e6aef828b0d0a4d97dece622c5f8e01f>.
 skip script test262/intl402/Intl/getCanonicalLocales/non-iana-canon.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1508684
 skip script test262/language/expressions/import.meta/syntax/invalid-assignment-target-update-expr.js
 
-# https://bugzilla.mozilla.org/show_bug.cgi?id=1542406
-skip script test262/language/expressions/class/elements/derived-cls-direct-eval-err-contains-supercall-1.js
-skip script test262/language/expressions/class/elements/derived-cls-direct-eval-err-contains-supercall-2.js
-skip script test262/language/expressions/class/elements/derived-cls-direct-eval-err-contains-supercall.js
+# https://github.com/tc39/test262/issues/2127
 skip script test262/language/expressions/class/elements/derived-cls-direct-eval-err-contains-superproperty-1.js
 skip script test262/language/expressions/class/elements/derived-cls-direct-eval-err-contains-superproperty-2.js
-skip script test262/language/expressions/class/elements/derived-cls-indirect-eval-err-contains-supercall-1.js
-skip script test262/language/expressions/class/elements/derived-cls-indirect-eval-err-contains-supercall-2.js
-skip script test262/language/expressions/class/elements/derived-cls-indirect-eval-err-contains-supercall.js
-skip script test262/language/expressions/class/elements/derived-cls-indirect-eval-err-contains-superproperty-1.js
-skip script test262/language/expressions/class/elements/derived-cls-indirect-eval-err-contains-superproperty-2.js
-skip script test262/language/expressions/class/elements/direct-eval-err-contains-arguments.js
-skip script test262/language/expressions/class/elements/private-derived-cls-direct-eval-err-contains-supercall-1.js
-skip script test262/language/expressions/class/elements/private-derived-cls-direct-eval-err-contains-supercall-2.js
-skip script test262/language/expressions/class/elements/private-derived-cls-direct-eval-err-contains-supercall.js
-skip script test262/language/expressions/class/elements/private-derived-cls-indirect-eval-err-contains-supercall-1.js
-skip script test262/language/expressions/class/elements/private-derived-cls-indirect-eval-err-contains-supercall-2.js
-skip script test262/language/expressions/class/elements/private-derived-cls-indirect-eval-err-contains-supercall.js
-skip script test262/language/statements/class/elements/derived-cls-direct-eval-err-contains-supercall-1.js
-skip script test262/language/statements/class/elements/derived-cls-direct-eval-err-contains-supercall-2.js
-skip script test262/language/statements/class/elements/derived-cls-direct-eval-err-contains-supercall.js
 skip script test262/language/statements/class/elements/derived-cls-direct-eval-err-contains-superproperty-1.js
 skip script test262/language/statements/class/elements/derived-cls-direct-eval-err-contains-superproperty-2.js
-skip script test262/language/statements/class/elements/derived-cls-indirect-eval-err-contains-supercall-1.js
-skip script test262/language/statements/class/elements/derived-cls-indirect-eval-err-contains-supercall-2.js
-skip script test262/language/statements/class/elements/derived-cls-indirect-eval-err-contains-supercall.js
-skip script test262/language/statements/class/elements/derived-cls-indirect-eval-err-contains-superproperty-1.js
-skip script test262/language/statements/class/elements/derived-cls-indirect-eval-err-contains-superproperty-2.js
-skip script test262/language/statements/class/elements/direct-eval-err-contains-arguments.js
-skip script test262/language/statements/class/elements/private-derived-cls-direct-eval-err-contains-supercall-1.js
-skip script test262/language/statements/class/elements/private-derived-cls-direct-eval-err-contains-supercall-2.js
-skip script test262/language/statements/class/elements/private-derived-cls-direct-eval-err-contains-supercall.js
-skip script test262/language/statements/class/elements/private-derived-cls-indirect-eval-err-contains-supercall-1.js
-skip script test262/language/statements/class/elements/private-derived-cls-indirect-eval-err-contains-supercall-2.js
-skip script test262/language/statements/class/elements/private-derived-cls-indirect-eval-err-contains-supercall.js
 
 
 ###########################################################
 # Tests disabled due to issues in test262 importer script #
 ###########################################################
 
 # test262 importer merges all includes in a per directory shell.js file, breaking this harness test case.
 skip script test262/harness/detachArrayBuffer.js
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -657,39 +657,43 @@ FunctionScope* FunctionScope::create(JSC
   // Copy it now that we're creating a permanent VM scope.
   Rooted<UniquePtr<Data>> data(
       cx, dataArg ? CopyScopeData<FunctionScope>(cx, dataArg)
                   : NewEmptyScopeData<FunctionScope>(cx));
   if (!data) {
     return nullptr;
   }
 
-  return createWithData(cx, &data, hasParameterExprs, needsEnvironment, fun,
-                        enclosing);
+  return createWithData(
+      cx, &data, hasParameterExprs,
+      dataArg ? dataArg->isFieldInitializer : IsFieldInitializer::No,
+      needsEnvironment, fun, enclosing);
 }
 
 /* static */
 FunctionScope* FunctionScope::createWithData(
     JSContext* cx, MutableHandle<UniquePtr<Data>> data, bool hasParameterExprs,
-    bool needsEnvironment, HandleFunction fun, HandleScope enclosing) {
+    IsFieldInitializer isFieldInitializer, bool needsEnvironment,
+    HandleFunction fun, HandleScope enclosing) {
   MOZ_ASSERT(data);
   MOZ_ASSERT(fun->isTenured());
 
   // FunctionScope::Data has GCManagedDeletePolicy because it contains a
   // GCPtr. Destruction of |data| below may trigger calls into the GC.
 
   RootedShape envShape(cx);
 
   BindingIter bi(*data, hasParameterExprs);
   uint32_t shapeFlags = FunctionScopeEnvShapeFlags(hasParameterExprs);
   if (!PrepareScopeData<FunctionScope>(cx, bi, data, &CallObject::class_,
                                        shapeFlags, &envShape)) {
     return nullptr;
   }
 
+  data->isFieldInitializer = isFieldInitializer;
   data->hasParameterExprs = hasParameterExprs;
   data->canonicalFunction.init(fun);
 
   // An environment may be needed regardless of existence of any closed over
   // bindings:
   //   - Extensible scopes (i.e., due to direct eval)
   //   - Needing a home object
   //   - Being a derived class constructor
@@ -764,37 +768,43 @@ XDRResult FunctionScope::XDR(XDRState<mo
   {
     Maybe<Rooted<UniquePtr<Data>>> uniqueData;
     if (mode == XDR_DECODE) {
       uniqueData.emplace(cx, data);
     }
 
     uint8_t needsEnvironment;
     uint8_t hasParameterExprs;
+    uint8_t isFieldInitializer;
     uint32_t nextFrameSlot;
     if (mode == XDR_ENCODE) {
       needsEnvironment = scope->hasEnvironment();
       hasParameterExprs = data->hasParameterExprs;
+      isFieldInitializer =
+          (data->isFieldInitializer == IsFieldInitializer::Yes ? 1 : 0);
       nextFrameSlot = data->nextFrameSlot;
     }
     MOZ_TRY(xdr->codeUint8(&needsEnvironment));
     MOZ_TRY(xdr->codeUint8(&hasParameterExprs));
+    MOZ_TRY(xdr->codeUint8(&isFieldInitializer));
     MOZ_TRY(xdr->codeUint16(&data->nonPositionalFormalStart));
     MOZ_TRY(xdr->codeUint16(&data->varStart));
     MOZ_TRY(xdr->codeUint32(&nextFrameSlot));
 
     if (mode == XDR_DECODE) {
       if (!data->length) {
         MOZ_ASSERT(!data->nonPositionalFormalStart);
         MOZ_ASSERT(!data->varStart);
         MOZ_ASSERT(!data->nextFrameSlot);
       }
 
-      scope.set(createWithData(cx, &uniqueData.ref(), hasParameterExprs,
-                               needsEnvironment, fun, enclosing));
+      scope.set(createWithData(
+          cx, &uniqueData.ref(), hasParameterExprs,
+          isFieldInitializer ? IsFieldInitializer::Yes : IsFieldInitializer::No,
+          needsEnvironment, fun, enclosing));
       if (!scope) {
         return xdr->fail(JS::TranscodeResult_Throw);
       }
 
       // nextFrameSlot is used only for this correctness check.
       MOZ_ASSERT(nextFrameSlot ==
                  scope->as<FunctionScope>().data().nextFrameSlot);
     }
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -77,16 +77,18 @@ enum class ScopeKind : uint8_t {
 
   // WasmInstanceScope
   WasmInstance,
 
   // WasmFunctionScope
   WasmFunction
 };
 
+enum class IsFieldInitializer : bool { No, Yes };
+
 static inline bool ScopeKindIsCatch(ScopeKind kind) {
   return kind == ScopeKind::SimpleCatch || kind == ScopeKind::Catch;
 }
 
 static inline bool ScopeKindIsInBody(ScopeKind kind) {
   return kind == ScopeKind::Lexical || kind == ScopeKind::SimpleCatch ||
          kind == ScopeKind::Catch || kind == ScopeKind::With ||
          kind == ScopeKind::FunctionBodyVar ||
@@ -516,16 +518,18 @@ class FunctionScope : public Scope {
     // often query properties of the JSFunction (e.g., is the function an
     // arrow).
     GCPtrFunction canonicalFunction = {};
 
     // If parameter expressions are present, parameters act like lexical
     // bindings.
     bool hasParameterExprs = false;
 
+    IsFieldInitializer isFieldInitializer = IsFieldInitializer::No;
+
     // Bindings are sorted by kind in both frames and environments.
     //
     // Positional formal parameter names are those that are not
     // destructured. They may be referred to by argument slots if
     // !script()->hasParameterExprs().
     //
     // An argument slot that needs to be skipped due to being destructured
     // or having defaults will have a nullptr name in the name array to
@@ -574,36 +578,38 @@ class FunctionScope : public Scope {
   static FunctionScope* clone(JSContext* cx, Handle<FunctionScope*> scope,
                               HandleFunction fun, HandleScope enclosing);
 
   template <XDRMode mode>
   static XDRResult XDR(XDRState<mode>* xdr, HandleFunction fun,
                        HandleScope enclosing, MutableHandleScope scope);
 
  private:
-  static FunctionScope* createWithData(JSContext* cx,
-                                       MutableHandle<UniquePtr<Data>> data,
-                                       bool hasParameterExprs,
-                                       bool needsEnvironment,
-                                       HandleFunction fun,
-                                       HandleScope enclosing);
+  static FunctionScope* createWithData(
+      JSContext* cx, MutableHandle<UniquePtr<Data>> data,
+      bool hasParameterExprs, IsFieldInitializer isFieldInitializer,
+      bool needsEnvironment, HandleFunction fun, HandleScope enclosing);
 
   Data& data() { return *static_cast<Data*>(data_); }
 
   const Data& data() const { return *static_cast<Data*>(data_); }
 
  public:
   uint32_t nextFrameSlot() const { return data().nextFrameSlot; }
 
   JSFunction* canonicalFunction() const { return data().canonicalFunction; }
 
   JSScript* script() const;
 
   bool hasParameterExprs() const { return data().hasParameterExprs; }
 
+  IsFieldInitializer isFieldInitializer() const {
+    return data().isFieldInitializer;
+  }
+
   uint32_t numPositionalFormalParameters() const {
     return data().nonPositionalFormalStart;
   }
 
   static bool isSpecialName(JSContext* cx, JSAtom* name);
 
   static Shape* getEmptyEnvironmentShape(JSContext* cx, bool hasParameterExprs);
 };