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/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/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/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/ValueExtractionSynthesizer.cpp b/lib/Interpreter/ValueExtractionSynthesizer.cpp index 9245ff2f4b..f1c34868cf 100644 --- a/lib/Interpreter/ValueExtractionSynthesizer.cpp +++ b/lib/Interpreter/ValueExtractionSynthesizer.cpp @@ -12,7 +12,6 @@ #include "cling/Interpreter/Interpreter.h" #include "cling/Interpreter/Transaction.h" #include "cling/Interpreter/Value.h" - #include "cling/Utils/AST.h" #include "clang/AST/ASTContext.h" @@ -167,13 +166,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); @@ -199,8 +203,8 @@ namespace { } Expr* ValueExtractionSynthesizer::SynthesizeSVRInit(Expr* E) { - if (!m_gClingVD) - FindAndCacheRuntimeDecls(); + if (!m_gClingVD && !FindAndCacheRuntimeDecls(E)) + return nullptr; // Build a reference to gCling ExprResult gClingDRE @@ -313,6 +317,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 +331,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 +394,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()); @@ -395,34 +406,54 @@ namespace { return Call.get(); } - void ValueExtractionSynthesizer::FindAndCacheRuntimeDecls() { + 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(clang::Expr* E) { 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(m_Sema, E, "cling namespace"); + if (!(NSD = utils::Lookup::Namespace(m_Sema, "runtime", NSD))) + 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(m_Sema, E, "cling::runtime::internal namespace"); } 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(m_Sema, E, "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(m_Sema, E, "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(m_Sema, E, "cling::runtime::internal::setValueWithAlloc"); + + m_UnresolvedWithAlloc = m_Sema->BuildDeclarationNameExpr(CSS, R, ADL).get(); + if (!m_UnresolvedWithAlloc) + return VSError(m_Sema, E, "cling::runtime::internal::setValueWithAlloc"); R.clear(); R.setLookupName(&m_Context->Idents.get("copyArray")); @@ -433,10 +464,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(m_Sema, E, "cling::runtime::internal::copyArray"); + + m_UnresolvedCopyArray = m_Sema->BuildDeclarationNameExpr(CSS, R, ADL).get(); + if (!m_UnresolvedCopyArray) + return VSError(m_Sema, E, "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..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. - void FindAndCacheRuntimeDecls(); + bool FindAndCacheRuntimeDecls(clang::Expr*); }; } // namespace cling diff --git a/lib/Interpreter/ValuePrinter.cpp b/lib/Interpreter/ValuePrinter.cpp index eb220f9e2b..ed9f60cfc9 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" @@ -54,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 = "<<>>"; } } @@ -144,22 +147,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,16 +596,15 @@ 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"; + // 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); - // 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."); - - return "ERROR in cling's callPrintValue(): missing value string."; + return valuePrinterInternal::kUndefined; } template @@ -863,7 +849,7 @@ namespace cling { } strm << "]"; } else - strm << "<<>> " << printAddress(value, '@'); + strm << valuePrinterInternal::kInvalid << ' ' << printAddress(value, '@'); return strm.str(); } @@ -871,16 +857,45 @@ 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) { - static bool includedRuntimePrintValue = false; // initialized only once as a static function variable + assert(V.getInterpreter() && "Invalid cling::Value"); + // 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. + // + // 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 && !Interp->getMacro("CLING_RUNTIME_PRINT_VALUE_H")) { + // 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()) + 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; + } } return printUnpackedClingValue(V); } 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..25c35843f6 100644 --- a/test/ErrorRecovery/ABI.C +++ b/test/ErrorRecovery/ABI.C @@ -6,12 +6,63 @@ // LICENSE.TXT for details. //------------------------------------------------------------------------------ -// 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 %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_RTIME_PRNT_ERR) + +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 + +#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; 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/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") diff --git a/test/Prompt/ValuePrinter/ExplicitInclude.C b/test/Prompt/ValuePrinter/ExplicitInclude.C new file mode 100644 index 0000000000..8dc3e70490 --- /dev/null +++ b/test/Prompt/ValuePrinter/ExplicitInclude.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 + +#include "cling/Interpreter/RuntimePrintValue.h" + +struct Trigger { } trgr +// CHECK: (struct Trigger &) @0x{{.*}} +.undo + +struct Trigger2 { } trgr +// CHECK-NEXT: (struct Trigger2 &) @0x{{.*}} +.undo + +/* FIXME: Need DeclUnloading fixes for this: +.undo // #include "cling/Interpreter/RuntimePrintValue.h" + +struct Trigger3 { } trgr +// DONT-CHECK-NEXT: (struct Trigger3 &) @0x{{.*}} +*/ + +// expected-no-diagnostics +.q diff --git a/test/Prompt/ValuePrinter/Regression.C b/test/Prompt/ValuePrinter/Regression.C index 414a15658f..37b143683b 100644 --- a/test/Prompt/ValuePrinter/Regression.C +++ b/test/Prompt/ValuePrinter/Regression.C @@ -89,7 +89,8 @@ 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}} // expected-error {{type name requires a specifier or qualifier}} diff --git a/test/Prompt/ValuePrinter/UndoPrint.C b/test/Prompt/ValuePrinter/UndoPrint.C new file mode 100755 index 0000000000..86e58b5b7e --- /dev/null +++ b/test/Prompt/ValuePrinter/UndoPrint.C @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +// 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 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: ` + +struct Trigger {}; +Trigger T0 +// CHECK-NEXT: (Trigger &) @0x{{[0-9a-f]+}} + +.stats undo +// CHECK-NEXT: +// CHECK-NEXT: ` +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: ` +// CHECK-NEXT: ` +// CHECK-NEXT: ` + + +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: +// CHECK-NEXT: ` + + +// expected-no-diagnostics +.q