From 276fda83a5d72c6283547708a2707049bfc8e647 Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Sun, 4 Feb 2018 02:21:53 -0500 Subject: [PATCH] Bug 530692 - Avoid EvalFunctionCall storing the evaluation for the implicit 'this' twice EvalFunctionCall.fImplicitThis is sometimes redundant in that the owner evaluation is already stored by one of the arguments. In such cases, storing the owner separately in fImplicitThis can lead to exponential complexity in chained method calls. We resolve the duplication by computing the implicit this from the function name evaluation instead of storing it where possible. This was already implemented for cases where the function name evaluation is an EvalMemberAccess in commit 659ff8c4a7c9. This commit extends the approach to cases where the function name evaluation is an EvalID. Change-Id: Ic71e81b4692c51ffb8e15b3da9fc2dff1a554f05 --- .../parser/tests/ast2/AST2TemplateTests.java | 75 +++++++++++++++++++ .../cpp/semantics/EvalFunctionCall.java | 16 +++- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index c1f8b07fbed..7afb03ee66f 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -10576,4 +10576,79 @@ public class AST2TemplateTests extends AST2CPPTestBase { public void testTemplateAliasWithVariadicArgs_530086b() throws Exception { parseAndCheckBindings(); } + + // template + // struct enable_if {}; + // + // template + // struct enable_if { typedef _Tp type; }; + // + // template _Tp&& declval(); + // + // template class function; + // + // template + // class function<_Res(_ArgTypes...)> + // { + // template()(declval<_ArgTypes>()...))> + // struct _Callable { }; + // + // public: + // template::value, void>::type> + // function(_Functor); + // }; + // + // void do_with_cql_env(function func); + // + // void test_range_queries() { + // do_with_cql_env([] (auto& e) { + // return e.create_table([](auto ks_name) { + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }).then([&e] { + // return e.foo(); + // }); + // }); + // } + public void testLongDependentFunctionCallChain_530692() throws Exception { + parseAndCheckBindings(); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionCall.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionCall.java index a110e575e0e..cc3970425b1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionCall.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionCall.java @@ -85,6 +85,8 @@ public final class EvalFunctionCall extends CPPDependentEvaluation { if (fArguments.length > 0) { if (fArguments[0] instanceof EvalMemberAccess) { return ((EvalMemberAccess) fArguments[0]).getOwnerEval(); + } else if (fArguments[0] instanceof EvalID) { + return ((EvalID) fArguments[0]).getFieldOwner(); } } @@ -221,6 +223,8 @@ public final class EvalFunctionCall extends CPPDependentEvaluation { if (args == fArguments) return this; + ICPPEvaluation implicitThis = fImplicitThis; + if (args[0] instanceof EvalFunctionSet && getOverload() == null) { // Resolve the function using the parameters of the function call. EvalFunctionSet functionSet = (EvalFunctionSet) args[0]; @@ -230,9 +234,19 @@ public final class EvalFunctionCall extends CPPDependentEvaluation { if (args[0] == EvalFixed.INCOMPLETE) { return args[0]; } + + // For functions sets of member functions, EvalFunctionSet does not store + // the value of the object on which the member function is called. + // If this value was previously elided (not stored explicitly in + // fImplicitThis to avoid duplication with the copy stored in fArguments[0]), + // starts storing it in fImplicitThis because *someone* needs to store + // the value for correct constexpr evaluation. + if (implicitThis == null) { + implicitThis = getImplicitThis(); + } } - ICPPEvaluation newImplicitThis = fImplicitThis != null ? fImplicitThis.instantiate(context, maxDepth) : null; + ICPPEvaluation newImplicitThis = implicitThis != null ? implicitThis.instantiate(context, maxDepth) : null; return new EvalFunctionCall(args, newImplicitThis, getTemplateDefinition()); }