diff --git a/interpreter/cling/include/cling/Interpreter/RuntimePrintValue.h b/interpreter/cling/include/cling/Interpreter/RuntimePrintValue.h index 590e621474f48..43d9dffd72f88 100644 --- a/interpreter/cling/include/cling/Interpreter/RuntimePrintValue.h +++ b/interpreter/cling/include/cling/Interpreter/RuntimePrintValue.h @@ -210,10 +210,20 @@ namespace cling { const void* M = TypeTest::isMap(obj); std::string str("{ "); - str += printValue(&(*iter), M); + + // If the dereferenced iterator points to the container itself, we have + // infinite recursion. This occurs with scalar values in nlohmann::json + auto printWithRecursionGuard = [obj](const auto* ptr, + const void* M) -> std::string { + if (static_cast(ptr) == static_cast(obj)) + return ""; + return printValue(ptr, M); + }; + + str += printWithRecursionGuard(&(*iter), M); while (++iter != iterEnd) { str += ", "; - str += printValue(&(*iter), M); + str += printWithRecursionGuard(&(*iter), M); } return str + " }"; } diff --git a/interpreter/cling/test/Prompt/ValuePrinter/Recursion.C b/interpreter/cling/test/Prompt/ValuePrinter/Recursion.C new file mode 100644 index 0000000000000..2e5a46a49103f --- /dev/null +++ b/interpreter/cling/test/Prompt/ValuePrinter/Recursion.C @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// CLING - the C++ LLVM-based InterpreterG :) +// +// This file is dual-licensed: you can choose to license it under the University +// of Illinois Open Source License or the GNU Lesser General Public License. See +// LICENSE.TXT for details. + +//------------------------------------------------------------------------------ + +// RUN: cat %s | %cling -Xclang -verify 2>&1 | FileCheck %s + +.rawInput 1 +// When begin() != end() but *begin() points to the container itself +// (in nlohmann::json), printValue_impl infinitely recurses without the +// self-reference check. + +class RecursionTest { +public: + RecursionTest() = default; + auto begin() const { return this; } // iterate over self + auto end() const { return this + 1; } // just to make sure begin() != end() +}; +.rawInput 0 + +RecursionTest j; +j +// CHECK: (RecursionTest &) { } + +// expected-no-diagnostics +.q