From 5c08f31832336c2375d89204b5512c5447ef66b7 Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Fri, 27 Jan 2017 15:17:24 -0500 Subject: [PATCH 01/10] Report executePrintValue errors with DiagnosticsEngine. --- lib/Interpreter/ValuePrinter.cpp | 32 +++++++-------------------- test/Prompt/ValuePrinter/Regression.C | 1 + 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/lib/Interpreter/ValuePrinter.cpp b/lib/Interpreter/ValuePrinter.cpp index eb220f9e2b..f0aa6b1ef3 100644 --- a/lib/Interpreter/ValuePrinter.cpp +++ b/lib/Interpreter/ValuePrinter.cpp @@ -23,6 +23,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "clang/Sema/SemaDiagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "llvm/Support/Format.h" @@ -144,22 +145,6 @@ struct AccessCtrlRAII_t { }; -#ifndef NDEBUG -/// Is typenam parsable? -bool canParseTypeName(cling::Interpreter& Interp, llvm::StringRef typenam) { - - AccessCtrlRAII_t AccessCtrlRAII(Interp); - - cling::Interpreter::CompilationResult Res - = Interp.declare("namespace { void* cling_printValue_Failure_Typename_check" - " = (void*)" + typenam.str() + "nullptr; }"); - if (Res != cling::Interpreter::kSuccess) - cling::errs() << "ERROR in cling::canParseTypeName(): " - "this typename cannot be spelled.\n"; - return Res == cling::Interpreter::kSuccess; -} -#endif - static std::string printDeclType(const clang::QualType& QT, const clang::NamedDecl* D) { if (!QT.hasQualifiers()) @@ -609,14 +594,13 @@ static std::string callPrintValue(const Value& V, const void* Val) { if (printValueV.isValid() && printValueV.getPtr()) return *(std::string *) printValueV.getPtr(); - // That didn't work. We probably diagnosed the issue as part of evaluate(). - cling::errs() <<"ERROR in cling's callPrintValue(): cannot pass value!\n"; - - // Check that the issue comes from an unparsable type name: lambdas, unnamed - // namespaces, types declared inside functions etc. Assert on everything - // else. - assert(!canParseTypeName(*Interp, getTypeString(V)) - && "printValue failed on a valid type name."); + // Probably diagnosed the issue as part of evaluate(), but make sure to + // mark the Sema with an error if not. + clang::DiagnosticsEngine& Diag = Interp->getDiagnostics(); + const unsigned ID = Diag.getCustomDiagID( + clang::DiagnosticsEngine::Level::Error, + "Could not execute cling::printValue with '%0'"); + Diag.Report(Interp->getSourceLocation(), ID) << getTypeString(V); return "ERROR in cling's callPrintValue(): missing value string."; } diff --git a/test/Prompt/ValuePrinter/Regression.C b/test/Prompt/ValuePrinter/Regression.C index 414a15658f..3c6bfc39b4 100644 --- a/test/Prompt/ValuePrinter/Regression.C +++ b/test/Prompt/ValuePrinter/Regression.C @@ -90,6 +90,7 @@ auto bla=[](double *x, double *par, int blub){return x[0]*blub;} // CHECK: ((lam #include using namespace std::placeholders; auto fn_moo = std::bind (bla, _1,_2,10) // CHECK: ERROR in cling's callPrintValue(): missing value string. +// expected-error {{Could not execute cling::printValue with '{{.*}}'}} // expected-error {{use of undeclared identifier 'lambda'}} // expected-error {{expected expression}} // expected-error {{type name requires a specifier or qualifier}} From 849b9fd4d0b2f2f60967bfa479fcdc1c49c7702a Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Fri, 27 Jan 2017 14:04:57 -0500 Subject: [PATCH 02/10] Fix crash when dumping an un-evaluated cling::Value and standardize string for undefined values. --- include/cling/Interpreter/RuntimePrintValue.h | 14 ++++++++------ lib/Interpreter/Value.cpp | 6 ++++++ lib/Interpreter/ValuePrinter.cpp | 8 ++++++-- test/Interfaces/evaluate.C | 4 +++- test/Prompt/ValuePrinter/Regression.C | 2 +- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/include/cling/Interpreter/RuntimePrintValue.h b/include/cling/Interpreter/RuntimePrintValue.h index fef612bfe1..db63986d36 100644 --- a/include/cling/Interpreter/RuntimePrintValue.h +++ b/include/cling/Interpreter/RuntimePrintValue.h @@ -21,14 +21,20 @@ namespace cling { class Value; + namespace valuePrinterInternal { + extern const char* const kEmptyCollection; + extern const char* const kUndefined; + } // General fallback - prints the address std::string printValue(const void *ptr); // Fallback for e.g. vector's bit iterator: template ::value>::type> - std::string printValue(const T& val) { return "{not representable}"; } + class = typename std::enable_if::value>::type> + std::string printValue(const T& val) { + return valuePrinterInternal::kUndefined; + } // void pointer std::string printValue(const void **ptr); @@ -114,10 +120,6 @@ namespace cling { // cling::Value std::string printValue(const Value *value); - namespace valuePrinterInternal { - extern const char* const kEmptyCollection; - } - // Collections internal namespace collectionPrinterInternal { diff --git a/lib/Interpreter/Value.cpp b/lib/Interpreter/Value.cpp index 6259ae697d..7eb4dbcb58 100644 --- a/lib/Interpreter/Value.cpp +++ b/lib/Interpreter/Value.cpp @@ -231,9 +231,15 @@ namespace cling { namespace valuePrinterInternal { std::string printTypeInternal(const Value& V); std::string printValueInternal(const Value& V); + extern const char* const kInvalid; } // end namespace valuePrinterInternal void Value::print(llvm::raw_ostream& Out, bool Escape) const { + if (!m_Interpreter) { + Out << valuePrinterInternal::kInvalid << "\n"; + return; + } + // Save the default type string representation so output can occur as one // operation (calling printValueInternal below may write to stderr). const std::string Type = valuePrinterInternal::printTypeInternal(*this); diff --git a/lib/Interpreter/ValuePrinter.cpp b/lib/Interpreter/ValuePrinter.cpp index f0aa6b1ef3..5a6a1209a5 100644 --- a/lib/Interpreter/ValuePrinter.cpp +++ b/lib/Interpreter/ValuePrinter.cpp @@ -55,6 +55,8 @@ extern "C" void cling_PrintValue(void * /*cling::Value**/ V) { namespace cling { namespace valuePrinterInternal { extern const char* const kEmptyCollection = "{}"; + extern const char* const kUndefined = "<<>>"; + extern const char* const kInvalid = "<<>>"; } } @@ -602,7 +604,7 @@ static std::string callPrintValue(const Value& V, const void* Val) { "Could not execute cling::printValue with '%0'"); Diag.Report(Interp->getSourceLocation(), ID) << getTypeString(V); - return "ERROR in cling's callPrintValue(): missing value string."; + return valuePrinterInternal::kUndefined; } template @@ -847,7 +849,7 @@ namespace cling { } strm << "]"; } else - strm << "<<>> " << printAddress(value, '@'); + strm << valuePrinterInternal::kInvalid << ' ' << printAddress(value, '@'); return strm.str(); } @@ -855,10 +857,12 @@ namespace cling { namespace valuePrinterInternal { std::string printTypeInternal(const Value &V) { + assert(V.getInterpreter() && "Invalid cling::Value"); return printQualType(V.getASTContext(), V.getType()); } std::string printValueInternal(const Value &V) { + assert(V.getInterpreter() && "Invalid cling::Value"); static bool includedRuntimePrintValue = false; // initialized only once as a static function variable // Include "RuntimePrintValue.h" only on the first printing. // This keeps the interpreter lightweight and reduces the startup time. diff --git a/test/Interfaces/evaluate.C b/test/Interfaces/evaluate.C index 558c9fc77d..edafa6ce4e 100644 --- a/test/Interfaces/evaluate.C +++ b/test/Interfaces/evaluate.C @@ -15,8 +15,10 @@ cling::Value V; V // CHECK: (cling::Value &) <<>> @0x{{.*}} +V.dump(); // CHECK-NEXT: <<>> + gCling->evaluate("return 1;", V); -V // CHECK: (cling::Value &) boxes [(int) 1] +V // CHECK-NEXT: (cling::Value &) boxes [(int) 1] gCling->evaluate("(void)V", V); V // CHECK-NEXT: (cling::Value &) boxes [(void) ] diff --git a/test/Prompt/ValuePrinter/Regression.C b/test/Prompt/ValuePrinter/Regression.C index 3c6bfc39b4..37b143683b 100644 --- a/test/Prompt/ValuePrinter/Regression.C +++ b/test/Prompt/ValuePrinter/Regression.C @@ -89,7 +89,7 @@ auto bla=[](double *x, double *par, int blub){return x[0]*blub;} // CHECK: ((lam #include using namespace std::placeholders; -auto fn_moo = std::bind (bla, _1,_2,10) // CHECK: ERROR in cling's callPrintValue(): missing value string. +auto fn_moo = std::bind (bla, _1,_2,10) // CHECK: <<>> // expected-error {{Could not execute cling::printValue with '{{.*}}'}} // expected-error {{use of undeclared identifier 'lambda'}} // expected-error {{expected expression}} From 80c87cc1c49fd0f1bf7937a490a5405809407e05 Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Sat, 23 Jul 2016 22:58:28 -0400 Subject: [PATCH 03/10] Propagate errors and report them a bit better in ValueExtractionSynthesizer::Transform. --- .../ValueExtractionSynthesizer.cpp | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/Interpreter/ValueExtractionSynthesizer.cpp b/lib/Interpreter/ValueExtractionSynthesizer.cpp index 9245ff2f4b..48f5ec1630 100644 --- a/lib/Interpreter/ValueExtractionSynthesizer.cpp +++ b/lib/Interpreter/ValueExtractionSynthesizer.cpp @@ -167,13 +167,18 @@ namespace cling { Expr* SVRInit = SynthesizeSVRInit(lastExpr); // if we had return stmt update to execute the SVR init, even if the // wrapper returns void. - if (RS) { - if (ImplicitCastExpr* VoidCast - = dyn_cast(RS->getRetValue())) - VoidCast->setSubExpr(SVRInit); + if (SVRInit) { + if (RS) { + if (ImplicitCastExpr* VoidCast + = dyn_cast(RS->getRetValue())) + VoidCast->setSubExpr(SVRInit); + } else + **I = SVRInit; + } else { + // FIXME: Do this atomically or something so that AST context will not + // contain Expr(s) that are unused for the rest of it's life. + return Result(D, false); } - else if (SVRInit) - **I = SVRInit; } } return Result(D, true); @@ -313,6 +318,8 @@ namespace { TypeSourceInfo* ETSI = m_Context->getTrivialTypeSourceInfo(ETy, noLoc); + assert(!Call.isInvalid() && "Invalid Call before building new"); + Call = m_Sema->BuildCXXNew(E->getSourceRange(), /*useGlobal ::*/true, /*placementLParen*/ noLoc, @@ -325,6 +332,12 @@ namespace { /*directInitRange*/E->getSourceRange(), /*initializer*/E ); + if (Call.isInvalid()) { + m_Sema->Diag(E->getLocStart(), diag::err_undeclared_var_use) + << "operator new"; + return Call.get(); + } + // Handle possible cleanups: Call = m_Sema->ActOnFinishFullExpr(Call.get()); } @@ -382,11 +395,10 @@ namespace { } } - assert(!Call.isInvalid() && "Invalid Call"); // Extend the scope of the temporary cleaner if applicable. - if (Cleanups) { + if (Cleanups && !Call.isInvalid()) { Cleanups->setSubExpr(Call.get()); Cleanups->setValueKind(Call.get()->getValueKind()); Cleanups->setType(Call.get()->getType()); From d84b4948ed57a06ef447d1b0c311453f47641ee6 Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Mon, 5 Jun 2017 23:21:33 -0400 Subject: [PATCH 04/10] Fix crash in ValueExtractionSynthesizer::FindAndCacheRuntimeDecls() and report errors. --- .../ValueExtractionSynthesizer.cpp | 65 +++++++++++++------ lib/Interpreter/ValueExtractionSynthesizer.h | 2 +- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/lib/Interpreter/ValueExtractionSynthesizer.cpp b/lib/Interpreter/ValueExtractionSynthesizer.cpp index 48f5ec1630..4bfb2aaffc 100644 --- a/lib/Interpreter/ValueExtractionSynthesizer.cpp +++ b/lib/Interpreter/ValueExtractionSynthesizer.cpp @@ -12,8 +12,8 @@ #include "cling/Interpreter/Interpreter.h" #include "cling/Interpreter/Transaction.h" #include "cling/Interpreter/Value.h" - #include "cling/Utils/AST.h" +#include "cling/Utils/Output.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclGroup.h" @@ -204,8 +204,8 @@ namespace { } Expr* ValueExtractionSynthesizer::SynthesizeSVRInit(Expr* E) { - if (!m_gClingVD) - FindAndCacheRuntimeDecls(); + if (!m_gClingVD && !FindAndCacheRuntimeDecls()) + return nullptr; // Build a reference to gCling ExprResult gClingDRE @@ -407,34 +407,54 @@ namespace { return Call.get(); } - void ValueExtractionSynthesizer::FindAndCacheRuntimeDecls() { + static bool VSError(const char* err) { + cling::errs() << "ValueExtractionSynthesizer error: " << err << ".\n"; + return false; + } + + bool ValueExtractionSynthesizer::FindAndCacheRuntimeDecls() { assert(!m_gClingVD && "Called multiple times!?"); DeclContext* NSD = m_Context->getTranslationUnitDecl(); + clang::VarDecl* clingVD = nullptr; if (m_Sema->getLangOpts().CPlusPlus) { - NSD = utils::Lookup::Namespace(m_Sema, "cling"); - NSD = utils::Lookup::Namespace(m_Sema, "runtime", NSD); - m_gClingVD = cast(utils::Lookup::Named(m_Sema, "gCling", NSD)); - NSD = utils::Lookup::Namespace(m_Sema, "internal",NSD); + if (!(NSD = utils::Lookup::Namespace(m_Sema, "cling"))) + return VSError("cling namespace not defined"); + if (!(NSD = utils::Lookup::Namespace(m_Sema, "runtime", NSD))) + return VSError("cling::runtime namespace not defined"); + if (!(clingVD = cast(utils::Lookup::Named(m_Sema, "gCling", + NSD)))) + return VSError("cling::runtime::gCling not defined"); + if (!NSD) + return VSError("cling::runtime namespace not defined"); + + if (!(NSD = utils::Lookup::Namespace(m_Sema, "internal", NSD))) + return VSError("cling::runtime::internal namespace not defined"); } LookupResult R(*m_Sema, &m_Context->Idents.get("setValueNoAlloc"), SourceLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); m_Sema->LookupQualifiedName(R, NSD); - assert(!R.empty() - && "Cannot find cling::runtime::internal::setValueNoAlloc"); + if (R.empty()) + return VSError("Cannot find cling::runtime::internal::setValueNoAlloc"); + const bool ADL = false; CXXScopeSpec CSS; - m_UnresolvedNoAlloc - = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).get(); + m_UnresolvedNoAlloc = m_Sema->BuildDeclarationNameExpr(CSS, R, ADL).get(); + if (!m_UnresolvedNoAlloc) + return VSError("Could not build cling::runtime::internal" + "::setValueNoAlloc"); R.clear(); R.setLookupName(&m_Context->Idents.get("setValueWithAlloc")); m_Sema->LookupQualifiedName(R, NSD); - assert(!R.empty() - && "Cannot find cling::runtime::internal::setValueWithAlloc"); - m_UnresolvedWithAlloc - = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).get(); + if (R.empty()) + return VSError("Cannot find cling::runtime::internal::setValueWithAlloc"); + + m_UnresolvedWithAlloc = m_Sema->BuildDeclarationNameExpr(CSS, R, ADL).get(); + if (!m_UnresolvedWithAlloc) + return VSError("Could not build cling::runtime::internal" + "::setValueWithAlloc"); R.clear(); R.setLookupName(&m_Context->Idents.get("copyArray")); @@ -445,10 +465,15 @@ namespace { // parent interpreter, but it will fail, because this is a template function. // Once the import of template functions becomes supported by clang, // this check can be de-activated. - if (!m_isChildInterpreter) - assert(!R.empty() && "Cannot find cling::runtime::internal::copyArray"); - m_UnresolvedCopyArray - = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).get(); + if (!m_isChildInterpreter && R.empty()) + return VSError("Cannot find cling::runtime::internal::copyArray"); + + m_UnresolvedCopyArray = m_Sema->BuildDeclarationNameExpr(CSS, R, ADL).get(); + if (!m_UnresolvedCopyArray) + return VSError("Could not build cling::runtime::internal::copyArray"); + + m_gClingVD = clingVD; + return true; } } // end namespace cling diff --git a/lib/Interpreter/ValueExtractionSynthesizer.h b/lib/Interpreter/ValueExtractionSynthesizer.h index f57562b75e..7fe868787c 100644 --- a/lib/Interpreter/ValueExtractionSynthesizer.h +++ b/lib/Interpreter/ValueExtractionSynthesizer.h @@ -90,7 +90,7 @@ namespace cling { // Find and cache cling::runtime::gCling, setValueNoAlloc, // setValueWithAlloc on first request. - void FindAndCacheRuntimeDecls(); + bool FindAndCacheRuntimeDecls(); }; } // namespace cling From 07279aa10fb0c7dc24421df53f9361403612da5e Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Thu, 8 Jun 2017 01:02:53 -0400 Subject: [PATCH 05/10] Report ValueExtractionSynthesizer errors with DiagnosticsEngine. --- .../ValueExtractionSynthesizer.cpp | 43 +++++++++---------- lib/Interpreter/ValueExtractionSynthesizer.h | 2 +- test/Driver/C.c | 5 ++- test/ErrorRecovery/ABI.C | 34 ++++++++++++++- 4 files changed, 59 insertions(+), 25 deletions(-) diff --git a/lib/Interpreter/ValueExtractionSynthesizer.cpp b/lib/Interpreter/ValueExtractionSynthesizer.cpp index 4bfb2aaffc..f1c34868cf 100644 --- a/lib/Interpreter/ValueExtractionSynthesizer.cpp +++ b/lib/Interpreter/ValueExtractionSynthesizer.cpp @@ -13,7 +13,6 @@ #include "cling/Interpreter/Transaction.h" #include "cling/Interpreter/Value.h" #include "cling/Utils/AST.h" -#include "cling/Utils/Output.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclGroup.h" @@ -204,7 +203,7 @@ namespace { } Expr* ValueExtractionSynthesizer::SynthesizeSVRInit(Expr* E) { - if (!m_gClingVD && !FindAndCacheRuntimeDecls()) + if (!m_gClingVD && !FindAndCacheRuntimeDecls(E)) return nullptr; // Build a reference to gCling @@ -407,28 +406,30 @@ namespace { return Call.get(); } - static bool VSError(const char* err) { - cling::errs() << "ValueExtractionSynthesizer error: " << err << ".\n"; + static bool VSError(clang::Sema* Sema, clang::Expr* E, llvm::StringRef Err) { + DiagnosticsEngine& Diags = Sema->getDiagnostics(); + Diags.Report(E->getLocStart(), + Diags.getCustomDiagID( + clang::DiagnosticsEngine::Level::Error, + "ValueExtractionSynthesizer could not find: '%0'.")) + << Err; return false; } - bool ValueExtractionSynthesizer::FindAndCacheRuntimeDecls() { + bool ValueExtractionSynthesizer::FindAndCacheRuntimeDecls(clang::Expr* E) { assert(!m_gClingVD && "Called multiple times!?"); DeclContext* NSD = m_Context->getTranslationUnitDecl(); clang::VarDecl* clingVD = nullptr; if (m_Sema->getLangOpts().CPlusPlus) { if (!(NSD = utils::Lookup::Namespace(m_Sema, "cling"))) - return VSError("cling namespace not defined"); + return VSError(m_Sema, E, "cling namespace"); if (!(NSD = utils::Lookup::Namespace(m_Sema, "runtime", NSD))) - return VSError("cling::runtime namespace not defined"); - if (!(clingVD = cast(utils::Lookup::Named(m_Sema, "gCling", - NSD)))) - return VSError("cling::runtime::gCling not defined"); - if (!NSD) - return VSError("cling::runtime namespace not defined"); - + return VSError(m_Sema, E, "cling::runtime namespace"); + if (!(clingVD = dyn_cast_or_null( + utils::Lookup::Named(m_Sema, "gCling", NSD)))) + return VSError(m_Sema, E, "cling::runtime::gCling"); if (!(NSD = utils::Lookup::Namespace(m_Sema, "internal", NSD))) - return VSError("cling::runtime::internal namespace not defined"); + return VSError(m_Sema, E, "cling::runtime::internal namespace"); } LookupResult R(*m_Sema, &m_Context->Idents.get("setValueNoAlloc"), SourceLocation(), Sema::LookupOrdinaryName, @@ -436,25 +437,23 @@ namespace { m_Sema->LookupQualifiedName(R, NSD); if (R.empty()) - return VSError("Cannot find cling::runtime::internal::setValueNoAlloc"); + return VSError(m_Sema, E, "cling::runtime::internal::setValueNoAlloc"); const bool ADL = false; CXXScopeSpec CSS; m_UnresolvedNoAlloc = m_Sema->BuildDeclarationNameExpr(CSS, R, ADL).get(); if (!m_UnresolvedNoAlloc) - return VSError("Could not build cling::runtime::internal" - "::setValueNoAlloc"); + return VSError(m_Sema, E, "cling::runtime::internal::setValueNoAlloc"); R.clear(); R.setLookupName(&m_Context->Idents.get("setValueWithAlloc")); m_Sema->LookupQualifiedName(R, NSD); if (R.empty()) - return VSError("Cannot find cling::runtime::internal::setValueWithAlloc"); + return VSError(m_Sema, E, "cling::runtime::internal::setValueWithAlloc"); m_UnresolvedWithAlloc = m_Sema->BuildDeclarationNameExpr(CSS, R, ADL).get(); if (!m_UnresolvedWithAlloc) - return VSError("Could not build cling::runtime::internal" - "::setValueWithAlloc"); + return VSError(m_Sema, E, "cling::runtime::internal::setValueWithAlloc"); R.clear(); R.setLookupName(&m_Context->Idents.get("copyArray")); @@ -466,11 +465,11 @@ namespace { // Once the import of template functions becomes supported by clang, // this check can be de-activated. if (!m_isChildInterpreter && R.empty()) - return VSError("Cannot find cling::runtime::internal::copyArray"); + return VSError(m_Sema, E, "cling::runtime::internal::copyArray"); m_UnresolvedCopyArray = m_Sema->BuildDeclarationNameExpr(CSS, R, ADL).get(); if (!m_UnresolvedCopyArray) - return VSError("Could not build cling::runtime::internal::copyArray"); + return VSError(m_Sema, E, "cling::runtime::internal::copyArray"); m_gClingVD = clingVD; return true; diff --git a/lib/Interpreter/ValueExtractionSynthesizer.h b/lib/Interpreter/ValueExtractionSynthesizer.h index 7fe868787c..077f393820 100644 --- a/lib/Interpreter/ValueExtractionSynthesizer.h +++ b/lib/Interpreter/ValueExtractionSynthesizer.h @@ -90,7 +90,7 @@ namespace cling { // Find and cache cling::runtime::gCling, setValueNoAlloc, // setValueWithAlloc on first request. - bool FindAndCacheRuntimeDecls(); + bool FindAndCacheRuntimeDecls(clang::Expr*); }; } // namespace cling diff --git a/test/Driver/C.c b/test/Driver/C.c index 8d6052b63d..ee30292049 100644 --- a/test/Driver/C.c +++ b/test/Driver/C.c @@ -16,5 +16,8 @@ int printf(const char*,...); printf("CHECK 123 %p\n", gCling); // CHECK: CHECK 123 -// expected-no-diagnostics +12 // expected-error {{ValueExtractionSynthesizer could not find: 'cling::runtime::internal::setValueNoAlloc'.}} + +32 // expected-error {{ValueExtractionSynthesizer could not find: 'cling::runtime::internal::setValueNoAlloc'.}} + .q diff --git a/test/ErrorRecovery/ABI.C b/test/ErrorRecovery/ABI.C index 488b5ff3e1..e8dc5817cd 100644 --- a/test/ErrorRecovery/ABI.C +++ b/test/ErrorRecovery/ABI.C @@ -7,11 +7,43 @@ //------------------------------------------------------------------------------ // RUN: %cling -C -E -P %s | %cling -nostdinc++ -Xclang -verify 2>&1 | FileCheck %s -// RUN: %cling -C -E -P -DCLING_NO_BUILTIN %s | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %s +// RUN: %cling -C -E -P -DCLING_VALEXTRACT_ERR %s | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %s +// RUN: %cling -C -E -P -DCLING_VALEXTRACT_ERR2 %s | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %s +// RUN: %cling -C -E -P -DCLING_VALEXTRACT_ERR3 %s | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %s +// RUN: %cling -C -E -P -DCLING_VALEXTRACT_ERR4 %s | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %s // expected-error@input_line_1:1 {{'new' file not found}} // CHECK: Warning in cling::IncrementalParser::CheckABICompatibility(): // CHECK-NEXT: Possible C++ standard library mismatch, compiled with {{.*$}} + +#if defined(CLING_VALEXTRACT_ERR) || defined(CLING_VALEXTRACT_ERR2) || \ + defined(CLING_VALEXTRACT_ERR3) || defined(CLING_VALEXTRACT_ERR4) + +struct Trigger {} Tr; + +#ifdef CLING_VALEXTRACT_ERR +Tr // expected-error@2 {{ValueExtractionSynthesizer could not find: 'cling namespace'.}} +#endif + +#ifdef CLING_VALEXTRACT_ERR2 +namespace cling {} +Tr // expected-error@2 {{ValueExtractionSynthesizer could not find: 'cling::runtime namespace'.}} +#endif + +#ifdef CLING_VALEXTRACT_ERR3 +namespace cling { namespace runtime {} } +Tr // expected-error@2 {{ValueExtractionSynthesizer could not find: 'cling::runtime::gCling'.}} +#endif + +#ifdef CLING_VALEXTRACT_ERR4 +namespace cling { namespace runtime { void* gCling; namespace internal { void* setValueWithAlloc; void* setValueNoAlloc; } } } +Tr // expected-error@2 {{ValueExtractionSynthesizer could not find: 'cling::runtime::internal::copyArray'.}} +// Make sure not to crash on subsequent attempts +Tr // expected-error@2 {{ValueExtractionSynthesizer could not find: 'cling::runtime::internal::copyArray'.}} +#endif + +#endif + .q From acb82864752c1f0cb6cdbcd2f75c49266976ab90 Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Sun, 4 Jun 2017 00:18:04 -0400 Subject: [PATCH 06/10] Fix crash if transactions are unloaded past the first printing of an expression. Fix crash when RuntimePrintValue.h cannot be loaded. Merge value-printing transactions with the transaction that invoked it. The latter fixes poor functionality in the .undo system where the user must have knowledge of how many transactions are added when an expression is printed. --- include/cling/Interpreter/Interpreter.h | 22 ++++++++ lib/Interpreter/IncrementalParser.cpp | 59 ++++++++++++++++++++++ lib/Interpreter/IncrementalParser.h | 7 +++ lib/Interpreter/Interpreter.cpp | 51 +++++++++++++++---- lib/Interpreter/ValuePrinter.cpp | 26 ++++++++-- test/Prompt/ValuePrinter/UndoPrint.C | 67 +++++++++++++++++++++++++ 6 files changed, 219 insertions(+), 13 deletions(-) create mode 100755 test/Prompt/ValuePrinter/UndoPrint.C diff --git a/include/cling/Interpreter/Interpreter.h b/include/cling/Interpreter/Interpreter.h index 0c23a90519..c3f80ee82c 100644 --- a/include/cling/Interpreter/Interpreter.h +++ b/include/cling/Interpreter/Interpreter.h @@ -102,6 +102,18 @@ namespace cling { ~StateDebuggerRAII(); }; + ///\brief Merge all transactions between construction and destruction + /// Use Prev to merge the Transactions with the last Transaction (true) + /// or the first Transaction created after instantiation (false). + class TransactionMergerRAII { + IncrementalParser& m_IncrParser; + const Transaction* m_T; + + public: + TransactionMergerRAII(Interpreter* Interp); + ~TransactionMergerRAII(); + }; + ///\brief Describes the return result of the different routines that do the /// incremental compilation. /// @@ -199,6 +211,7 @@ namespace cling { enum { kStdStringTransaction = 0, // Transaction known to contain std::string + kPrintValueTransaction, // Transaction that included RuntimePrintValue.h kNumTransactions }; mutable const Transaction* m_CachedTrns[kNumTransactions] = {}; @@ -780,6 +793,15 @@ namespace cling { [](const clang::PresumedLoc&) { return false;}) const; friend class runtime::internal::LifetimeHandler; + + ///\brief Used by valuePrinterInternal::printValueInternal to mark when the + /// value printing headers were included. + /// + ///\returns reference to m_CachedTrns[kPrintValueTransaction] + /// + const Transaction*& printValueTransaction() { + return m_CachedTrns[kPrintValueTransaction]; + } }; } // namespace cling diff --git a/lib/Interpreter/IncrementalParser.cpp b/lib/Interpreter/IncrementalParser.cpp index f0ed07d83b..aafa63b2ad 100644 --- a/lib/Interpreter/IncrementalParser.cpp +++ b/lib/Interpreter/IncrementalParser.cpp @@ -280,6 +280,65 @@ namespace cling { return m_Consumer->getTransaction(); } + void + IncrementalParser::mergeTransactionsAfter(const Transaction *T) { + bool Found = false; + llvm::SmallVector Merge; + for (auto Itr = m_Transactions.rbegin(), End = m_Transactions.rend(); + Itr != End; ++Itr) { + Transaction *Cur = *Itr; + Merge.push_back(Cur); + if ((Found = (Cur == T))) + break; + } + if (!Found) { + clang::DiagnosticsEngine& Diags = m_Interpreter->getDiagnostics(); + const auto ID = Diags.getCustomDiagID(clang::DiagnosticsEngine::Warning, + "Transaction was not found."); + Diags.Report(m_Interpreter->getSourceLocation(), ID); + return; // Unused: nullptr + } + if (Merge.empty()) { + // Trying to merge the last Transaction with nothing following. + return; // Unused: getCurrentTransaction(); + } + assert(!T->isNestedTransaction() && "New parent cannot be a child."); + + auto Itr = Merge.rbegin(); + Transaction *Parent = *Itr; + ++Itr; + for (auto End = Merge.rend(); Itr != End; ++Itr) { + Transaction *CurChild = *Itr; + // Try to keep everything current + if (m_Consumer->getTransaction() == CurChild) + m_Consumer->setTransaction(Parent); + + // Keep parents in place + while (CurChild->getParent()) + CurChild = CurChild->getParent(); + + // FIXME: Propogate child's error state into parent. Note the CurChild + // error state will have to be saved here, as once addNestedTransaction + // has finished it can no longer be retrieved. + // + // Just force diag states to match until there's a decent test case + assert((CurChild->getIssuedDiags() != Transaction::kErrors || + Parent->getIssuedDiags() == Transaction::kErrors) + && "Cannot merge transactions with different error states"); + + Parent->addNestedTransaction(CurChild); + + // Move whatever the CurChild.Next is into Parent + Parent->setNext(const_cast(CurChild->getNext())); + // And make sure the CurChild.Next is empty + CurChild->setNext(nullptr); + + m_Transactions.pop_back(); + } + assert(Parent->getNext() == nullptr && "Parent still has next"); + return; // Unused: parent; + } + SourceLocation IncrementalParser::getLastMemoryBufferEndLoc() const { const SourceManager& SM = getCI()->getSourceManager(); SourceLocation Result = SM.getLocForStartOfFile(m_VirtualFileID); diff --git a/lib/Interpreter/IncrementalParser.h b/lib/Interpreter/IncrementalParser.h index 0d76c32a29..4bd1ba1731 100644 --- a/lib/Interpreter/IncrementalParser.h +++ b/lib/Interpreter/IncrementalParser.h @@ -176,6 +176,13 @@ namespace cling { return m_Transactions.back(); } + ///\brief Merge transactions after the one given. + /// + ///\param[in] T - transactions after which to merge + ///\returns the parent transaction of the merge. + /// + void mergeTransactionsAfter(const Transaction *T); + ///\brief Returns the currently active transaction. /// const Transaction* getCurrentTransaction() const; diff --git a/lib/Interpreter/Interpreter.cpp b/lib/Interpreter/Interpreter.cpp index 50965d7156..841a9cb031 100644 --- a/lib/Interpreter/Interpreter.cpp +++ b/lib/Interpreter/Interpreter.cpp @@ -141,6 +141,13 @@ namespace cling { } } + Interpreter::TransactionMergerRAII::TransactionMergerRAII(Interpreter* I) : + m_IncrParser(*I->m_IncrParser), m_T(m_IncrParser.getLastTransaction()) {} + + Interpreter::TransactionMergerRAII::~TransactionMergerRAII() { + m_IncrParser.mergeTransactionsAfter(m_T); + } + const Parser& Interpreter::getParser() const { return *m_IncrParser->getParser(); } @@ -1193,20 +1200,42 @@ namespace cling { return kSuccess; } + const Transaction *printTBefore = m_CachedTrns[kPrintValueTransaction]; + Value resultV; if (!V) V = &resultV; if (!lastT->getWrapperFD()) // no wrapper to run return Interpreter::kSuccess; - else if (RunFunction(lastT->getWrapperFD(), V) < kExeFirstError){ - if (lastT->getCompilationOpts().ValuePrinting - != CompilationOptions::VPDisabled - && V->isValid() - // the !V->needsManagedAllocation() case is handled by - // dumpIfNoStorage. - && V->needsManagedAllocation()) - V->dump(); - return Interpreter::kSuccess; + else { + ExecutionResult rslt = RunFunction(lastT->getWrapperFD(), V); + + // If print value Transaction has changed value, then lastT is now + // the transaction that holds the transaction(s) of loading up the + // value printer and must be recorded as such. + if (printTBefore != m_CachedTrns[kPrintValueTransaction]) { + assert(m_CachedTrns[kPrintValueTransaction] != nullptr + && "Value printer failed to load after success?"); + // As the stack is unwound from recursive calls to EvaluateInternal + // we merge the subsequent transactions into the current one. + // Then m_CachedTrns[kPrintValue] is marked as this transaction as it + // is the first known Transaction that caused the printer to be loaded. + m_IncrParser->mergeTransactionsAfter(lastT); + m_CachedTrns[kPrintValueTransaction] = lastT; + assert(!m_CachedTrns[kPrintValueTransaction]->isNestedTransaction() && + "Print value transaction is not topmost parent"); + } + + if ( rslt < kExeFirstError) { + if (lastT->getCompilationOpts().ValuePrinting + != CompilationOptions::VPDisabled + && V->isValid() + // the !V->needsManagedAllocation() case is handled by + // dumpIfNoStorage. + && V->needsManagedAllocation()) + V->dump(); + return Interpreter::kSuccess; + } } return Interpreter::kSuccess; } @@ -1355,6 +1384,10 @@ namespace cling { << i << " of " << numberOfTransactions << "\n"; return; } + // Mark Interpreter as not having loaded 'RuntimePrintValue.h' + if (T == m_CachedTrns[kPrintValueTransaction]) + m_CachedTrns[kPrintValueTransaction] = nullptr; + unload(*T); } } diff --git a/lib/Interpreter/ValuePrinter.cpp b/lib/Interpreter/ValuePrinter.cpp index 5a6a1209a5..7d743c3d89 100644 --- a/lib/Interpreter/ValuePrinter.cpp +++ b/lib/Interpreter/ValuePrinter.cpp @@ -863,12 +863,30 @@ namespace cling { std::string printValueInternal(const Value &V) { assert(V.getInterpreter() && "Invalid cling::Value"); - static bool includedRuntimePrintValue = false; // initialized only once as a static function variable + // Include "RuntimePrintValue.h" only on the first printing. // This keeps the interpreter lightweight and reduces the startup time. - if (!includedRuntimePrintValue) { - V.getInterpreter()->declare("#include \"cling/Interpreter/RuntimePrintValue.h\""); - includedRuntimePrintValue = true; + // But user can undo past the transaction that invoked this, so whether + // we are first or not is known by the interpreter. + // + // Additionally add any transactions that occur in this scope as + // children to the transaction that invoked us + + Interpreter* Interp = V.getInterpreter(); + Interpreter::TransactionMergerRAII M(Interp); + const Transaction*& T = Interp->printValueTransaction(); + if (!T) { + // DiagnosticErrorTrap Trap(Interp->getSema().getDiagnostics()); + Interp->declare("#include \"cling/Interpreter/RuntimePrintValue.h\"", + const_cast(&T)); + if (!T) { + // Should also check T->getIssuedDiags() == Transaction::kErrors)? + + // It's redundant, but nicer to see the error at the bottom. + // if (!Trap.hasErrorOccurred()) + cling::errs() << "RuntimePrintValue.h could not be loaded.\n"; + return kUndefined; + } } return printUnpackedClingValue(V); } diff --git a/test/Prompt/ValuePrinter/UndoPrint.C b/test/Prompt/ValuePrinter/UndoPrint.C new file mode 100755 index 0000000000..2638d122f0 --- /dev/null +++ b/test/Prompt/ValuePrinter/UndoPrint.C @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------------ +// 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 +// Test undoPrinter + +.stats undo +// CHECK: +// CHECK-NEXT: ` + +const char *message = "winkey"; + +message +// CHECK-NEXT: (const char *) "winkey" + +.undo + +// Make sure we can still print +message +// CHECK-NEXT: (const char *) "winkey" + +.undo +.stats undo +// CHECK-NEXT: +// CHECK-NEXT: ` +// CHECK-NEXT: + +message +// CHECK-NEXT: (const char *) "winkey" + +.undo // print message +.undo // decalre message +.stats undo +// CHECK-NEXT: +// CHECK-NEXT: ` + +#include "cling/Interpreter/Interpreter.h" + +gCling->echo("1;"); +// CHECK-NEXT: (int) 1 + +.stats undo +// CHECK-NEXT: +// CHECK-NEXT: ` +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: ` +// CHECK-NEXT: ` +// CHECK-NEXT: ` +// CHECK-NEXT: ` + +.undo +.stats undo +// CHECK-NEXT: +// CHECK-NEXT: ` +// CHECK-NEXT: + +gCling->echo("1;"); +// CHECK-NEXT: (int) 1 + +// expected-no-diagnostics +.q From 32000baf4b5e9f62749c684fd21f65911c6f9cfd Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Sun, 24 Jul 2016 00:25:21 -0400 Subject: [PATCH 07/10] Use DiagnosticsEngine to report error when RuntimePrintValue.h cannot be loaded. --- lib/Interpreter/ValuePrinter.cpp | 8 +++-- test/ErrorRecovery/ABI.C | 33 +++++++++++++++---- .../ABI/cling/Interpreter/RuntimePrintValue.h | 2 ++ 3 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 test/ErrorRecovery/ABI/cling/Interpreter/RuntimePrintValue.h diff --git a/lib/Interpreter/ValuePrinter.cpp b/lib/Interpreter/ValuePrinter.cpp index 7d743c3d89..27072bde98 100644 --- a/lib/Interpreter/ValuePrinter.cpp +++ b/lib/Interpreter/ValuePrinter.cpp @@ -881,10 +881,14 @@ namespace cling { const_cast(&T)); if (!T) { // Should also check T->getIssuedDiags() == Transaction::kErrors)? - + // It's redundant, but nicer to see the error at the bottom. // if (!Trap.hasErrorOccurred()) - cling::errs() << "RuntimePrintValue.h could not be loaded.\n"; + clang::DiagnosticsEngine& Diag = Interp->getDiagnostics(); + const unsigned ID = Diag.getCustomDiagID( + clang::DiagnosticsEngine::Level::Error, + "RuntimePrintValue.h could not be loaded"); + Diag.Report(Interp->getSourceLocation(), ID); return kUndefined; } } diff --git a/test/ErrorRecovery/ABI.C b/test/ErrorRecovery/ABI.C index e8dc5817cd..25c35843f6 100644 --- a/test/ErrorRecovery/ABI.C +++ b/test/ErrorRecovery/ABI.C @@ -6,20 +6,34 @@ // LICENSE.TXT for details. //------------------------------------------------------------------------------ -// RUN: %cling -C -E -P %s | %cling -nostdinc++ -Xclang -verify 2>&1 | FileCheck %s -// RUN: %cling -C -E -P -DCLING_VALEXTRACT_ERR %s | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %s -// RUN: %cling -C -E -P -DCLING_VALEXTRACT_ERR2 %s | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %s -// RUN: %cling -C -E -P -DCLING_VALEXTRACT_ERR3 %s | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %s -// RUN: %cling -C -E -P -DCLING_VALEXTRACT_ERR4 %s | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %s +// RUN: %cling -C -E -P %s > %t +// RUN: cat %t | %cling -nostdinc++ -Xclang -verify 2>&1 | FileCheck %t +// RUN: %cling -C -E -P -DCLING_VALEXTRACT_ERR %s > %t +// RUN: cat %t | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %t + +// RUN: %cling -C -E -P -DCLING_VALEXTRACT_ERR2 %s > %t +// RUN: cat %t | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %t + +// RUN: %cling -C -E -P -DCLING_VALEXTRACT_ERR3 %s > %t +// RUN: cat %t | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %t + +// RUN: %cling -C -E -P -DCLING_VALEXTRACT_ERR4 %s > %t +// RUN: cat %t | %cling -nostdinc++ -nobuiltininc -Xclang -verify 2>&1 | FileCheck %t + +// RUN: %cling -C -E -P -DCLING_RTIME_PRNT_ERR %s > %t +// RUN: cat %t | %cling -I%S/ABI -Xclang -verify 2>&1 | FileCheck %t + +#ifndef CLING_RTIME_PRNT_ERR // expected-error@input_line_1:1 {{'new' file not found}} // CHECK: Warning in cling::IncrementalParser::CheckABICompatibility(): // CHECK-NEXT: Possible C++ standard library mismatch, compiled with {{.*$}} - +#endif #if defined(CLING_VALEXTRACT_ERR) || defined(CLING_VALEXTRACT_ERR2) || \ - defined(CLING_VALEXTRACT_ERR3) || defined(CLING_VALEXTRACT_ERR4) + defined(CLING_VALEXTRACT_ERR3) || defined(CLING_VALEXTRACT_ERR4) || \ + defined(CLING_RTIME_PRNT_ERR) struct Trigger {} Tr; @@ -46,4 +60,9 @@ Tr // expected-error@2 {{ValueExtractionSynthesizer could not find: 'cling::runt #endif +#ifdef CLING_RTIME_PRNT_ERR +Tr // expected-error@cling/Interpreter/RuntimePrintValue.h:2 {{C++ requires a type specifier for all declarations}} expected-error@2 {{RuntimePrintValue.h could not be loaded}} +// CHECK: (struct Trigger &) <<>> +#endif + .q diff --git a/test/ErrorRecovery/ABI/cling/Interpreter/RuntimePrintValue.h b/test/ErrorRecovery/ABI/cling/Interpreter/RuntimePrintValue.h new file mode 100644 index 0000000000..7096425949 --- /dev/null +++ b/test/ErrorRecovery/ABI/cling/Interpreter/RuntimePrintValue.h @@ -0,0 +1,2 @@ +// Simulate an error parsing the real RuntimePrintValue.h +ERROR; From 41fc3b7772e8291d0811432e7670099998be38e6 Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Sun, 4 Jun 2017 00:18:06 -0400 Subject: [PATCH 08/10] Check if CLING_RUNTIME_PRINT_VALUE_H defined before including RuntimePrintValue.h. --- lib/Interpreter/ValuePrinter.cpp | 11 ++++++--- test/Prompt/ValuePrinter/ExplicitInclude.C | 28 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 test/Prompt/ValuePrinter/ExplicitInclude.C diff --git a/lib/Interpreter/ValuePrinter.cpp b/lib/Interpreter/ValuePrinter.cpp index 27072bde98..ed9f60cfc9 100644 --- a/lib/Interpreter/ValuePrinter.cpp +++ b/lib/Interpreter/ValuePrinter.cpp @@ -869,13 +869,18 @@ namespace cling { // But user can undo past the transaction that invoked this, so whether // we are first or not is known by the interpreter. // - // Additionally add any transactions that occur in this scope as - // children to the transaction that invoked us + // When printing has already occured once or RuntimePrintValue.h was + // explicitly included, then Transaction merging has to occur here. + // + // Additionally the user could have included RuntimePrintValue.h before + // this code is run, so if there is no print transaction, check if + // CLING_RUNTIME_PRINT_VALUE_H is defined. + // FIXME: Relying on this macro isn't the best, but what's another way? Interpreter* Interp = V.getInterpreter(); Interpreter::TransactionMergerRAII M(Interp); const Transaction*& T = Interp->printValueTransaction(); - if (!T) { + if (!T && !Interp->getMacro("CLING_RUNTIME_PRINT_VALUE_H")) { // DiagnosticErrorTrap Trap(Interp->getSema().getDiagnostics()); Interp->declare("#include \"cling/Interpreter/RuntimePrintValue.h\"", const_cast(&T)); diff --git a/test/Prompt/ValuePrinter/ExplicitInclude.C b/test/Prompt/ValuePrinter/ExplicitInclude.C new file mode 100644 index 0000000000..dcb2e1ab5e --- /dev/null +++ b/test/Prompt/ValuePrinter/ExplicitInclude.C @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// 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 + +#include "cling/Interpreter/RuntimePrintValue.h" + +struct Trigger { } trgr +// CHECK: (struct Trigger &) @0x{{.*}} +.undo + +struct Trigger2 { } trgr +// CHECK-NEXT: (struct Trigger2 &) @0x{{.*}} +.undo + +.undo // #include "cling/Interpreter/RuntimePrintValue.h" + +struct Trigger3 { } trgr +// CHECK-NEXT: (struct Trigger3 &) @0x{{.*}} + +// expected-no-diagnostics +.q From 9a6782d24b20b4bdc3b939d76a423ffa7c041ddd Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Sun, 4 Jun 2017 00:18:05 -0400 Subject: [PATCH 09/10] Fix undo value printing tests for CERN/master. --- test/Prompt/ValuePrinter/ExplicitInclude.C | 4 +- test/Prompt/ValuePrinter/UndoPrint.C | 47 +++++++--------------- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/test/Prompt/ValuePrinter/ExplicitInclude.C b/test/Prompt/ValuePrinter/ExplicitInclude.C index dcb2e1ab5e..8dc3e70490 100644 --- a/test/Prompt/ValuePrinter/ExplicitInclude.C +++ b/test/Prompt/ValuePrinter/ExplicitInclude.C @@ -19,10 +19,12 @@ struct Trigger2 { } trgr // CHECK-NEXT: (struct Trigger2 &) @0x{{.*}} .undo +/* FIXME: Need DeclUnloading fixes for this: .undo // #include "cling/Interpreter/RuntimePrintValue.h" struct Trigger3 { } trgr -// CHECK-NEXT: (struct Trigger3 &) @0x{{.*}} +// DONT-CHECK-NEXT: (struct Trigger3 &) @0x{{.*}} +*/ // expected-no-diagnostics .q diff --git a/test/Prompt/ValuePrinter/UndoPrint.C b/test/Prompt/ValuePrinter/UndoPrint.C index 2638d122f0..86e58b5b7e 100755 --- a/test/Prompt/ValuePrinter/UndoPrint.C +++ b/test/Prompt/ValuePrinter/UndoPrint.C @@ -7,61 +7,44 @@ //------------------------------------------------------------------------------ // RUN: cat %s | %cling -Xclang -verify 2>&1 | FileCheck %s -// Test undoPrinter +// Test Check the ability to undo past runtime printing. + +// FIXME: +// Unloading past first print Transaction can fail due to decl unloading. +// Currently this test only validates that printing Transactions are properly +// compressed/parented into one atomic undo-able Transaction. .stats undo // CHECK: // CHECK-NEXT: ` -const char *message = "winkey"; - -message -// CHECK-NEXT: (const char *) "winkey" - -.undo - -// Make sure we can still print -message -// CHECK-NEXT: (const char *) "winkey" +struct Trigger {}; +Trigger T0 +// CHECK-NEXT: (Trigger &) @0x{{[0-9a-f]+}} -.undo .stats undo // CHECK-NEXT: // CHECK-NEXT: ` // CHECK-NEXT: - -message -// CHECK-NEXT: (const char *) "winkey" - -.undo // print message -.undo // decalre message -.stats undo // CHECK-NEXT: // CHECK-NEXT: ` +// CHECK-NEXT: ` +// CHECK-NEXT: ` -#include "cling/Interpreter/Interpreter.h" - -gCling->echo("1;"); -// CHECK-NEXT: (int) 1 +Trigger T1 +// CHECK-NEXT: (Trigger &) @0x{{[0-9a-f]+}} .stats undo // CHECK-NEXT: // CHECK-NEXT: ` // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: ` -// CHECK-NEXT: ` -// CHECK-NEXT: ` -// CHECK-NEXT: ` - -.undo -.stats undo -// CHECK-NEXT: +// CHECK-NEXT: ` // CHECK-NEXT: ` // CHECK-NEXT: +// CHECK-NEXT: ` -gCling->echo("1;"); -// CHECK-NEXT: (int) 1 // expected-no-diagnostics .q From 501aad99ef58859b48b6fddeb058d36f2639a0a6 Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Sat, 24 Jun 2017 20:43:59 -0400 Subject: [PATCH 10/10] Partially revert "Fix test for CERN/master." --- test/Pragmas/multiArgument.C | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/test/Pragmas/multiArgument.C b/test/Pragmas/multiArgument.C index d1d42167b4..2910829eaa 100644 --- a/test/Pragmas/multiArgument.C +++ b/test/Pragmas/multiArgument.C @@ -28,11 +28,6 @@ ValueC .undo .undo -// FIXME: When print Transactions are properly parenteted remove these -.undo -.undo -.undo - ValueA // expected-error {{use of undeclared identifier 'ValueA'}} #pragma cling load "P0.h" "P1.h" "P2.h" @@ -50,11 +45,6 @@ ValueC .undo .undo -// FIXME: When print Transactions are properly parenteted remove these -.undo -.undo -.undo - ValueB // expected-error {{use of undeclared identifier 'ValueB'}} #pragma cling(load, "P0.h", "P1.h", "P2.h")