diff --git a/core/metacling/src/TCling.cxx b/core/metacling/src/TCling.cxx index 904b85242bc9d..a8df36467e8c1 100644 --- a/core/metacling/src/TCling.cxx +++ b/core/metacling/src/TCling.cxx @@ -2663,7 +2663,7 @@ Longptr_t TCling::ProcessLine(const char* line, EErrorCode* error/*=0*/) code += codeline + "\n"; } unnamedMacroOpenCurly - = cling::utils::isUnnamedMacro(code, fInterpreter->getCI()->getLangOpts()); + = cling::utils::isUnnamedMacro(code, fInterpreter->getCI()->getSourceManager(), fInterpreter->getCI()->getPreprocessor()); } fCurExecutingMacros.push_back(fname); diff --git a/interpreter/cling/include/cling/Utils/SourceNormalization.h b/interpreter/cling/include/cling/Utils/SourceNormalization.h index dde8cb326cba0..8a5e5a9a752ec 100644 --- a/interpreter/cling/include/cling/Utils/SourceNormalization.h +++ b/interpreter/cling/include/cling/Utils/SourceNormalization.h @@ -20,6 +20,7 @@ namespace clang { class LangOptions; class SourceLocation; class SourceManager; + class Preprocessor; } namespace cling { @@ -29,6 +30,7 @@ namespace utils { /// Unnamed macros contain no function definition, but "prompt-style" code /// surrounded by a set of curly braces. /// + /// \note Preprocessing macros are ignored /// \param source The source code to analyze. /// \param LangOpts - LangOptions to use for lexing. /// \return the position of the unnamed macro's opening '{'; or @@ -36,6 +38,20 @@ namespace utils { size_t isUnnamedMacro(llvm::StringRef source, clang::LangOptions& LangOpts); + ///\brief Determine whether the source is an unnamed macro. + /// + /// Unnamed macros contain no function definition, but "prompt-style" code + /// surrounded by a set of curly braces. + /// + /// \note Preprocessing macros are fully evaluated + /// \param source The source code to analyze. + /// \param sm - source manager to use for lexing. + /// \param pp - preprocessor to use for lexing. + /// \return the position of the unnamed macro's opening '{'; or + /// std::string::npos if this is not an unnamed macro. + size_t isUnnamedMacro(llvm::StringRef source, clang::SourceManager& sm, + clang::Preprocessor& pp); + ///\brief Determine whether the source needs to be moved into a function. /// /// If so, move possible includes directives out of the future body of the diff --git a/interpreter/cling/lib/MetaProcessor/MetaProcessor.cpp b/interpreter/cling/lib/MetaProcessor/MetaProcessor.cpp index 701c5555998f0..555a52dc686ca 100644 --- a/interpreter/cling/lib/MetaProcessor/MetaProcessor.cpp +++ b/interpreter/cling/lib/MetaProcessor/MetaProcessor.cpp @@ -433,12 +433,12 @@ namespace cling { } if (posOpenCurly != (size_t)-1 && !content.empty()) { - assert(content[posOpenCurly] == '{' - && "No curly at claimed position of opening curly!"); + assert(posOpenCurly < content.length() && content[posOpenCurly] == '{' && + "No curly at claimed position of opening curly!"); // hide the curly brace: content[posOpenCurly] = ' '; // and the matching closing '}' - size_t posCloseCurly = content.find_last_not_of(whitespace); + size_t posCloseCurly = content.find_last_not_of(whitespace); // TODO replace instead with preprocessed one, isUnnamedMacro should return tuple start and stop, rather than researching here if (posCloseCurly != std::string::npos) { if (content[posCloseCurly] == ';' && content[posCloseCurly-1] == '}') { content[posCloseCurly--] = ' '; // replace ';' and enter next if diff --git a/interpreter/cling/lib/Utils/SourceNormalization.cpp b/interpreter/cling/lib/Utils/SourceNormalization.cpp index c2f1251d1946e..6e95a8e251ace 100644 --- a/interpreter/cling/lib/Utils/SourceNormalization.cpp +++ b/interpreter/cling/lib/Utils/SourceNormalization.cpp @@ -12,6 +12,7 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" #include @@ -443,7 +444,28 @@ cling::utils::isUnnamedMacro(llvm::StringRef source, return std::string::npos; } - +size_t cling::utils::isUnnamedMacro(llvm::StringRef source, + clang::SourceManager& sm, + clang::Preprocessor& pp) { + std::unique_ptr buf = + llvm::MemoryBuffer::getMemBufferCopy(source, + "unnamed_macro_candidate_buffer"); + clang::FileID fid = sm.createFileID(std::move(buf)); + pp.EnterSourceFile(fid, nullptr, clang::SourceLocation()); + clang::Token tok; + do { + pp.Lex(tok); // Lexes while expanding macros and skipping false #if paths + // automatically + if (tok.is(tok::comment)) + continue; // ignore comments + if (tok.is(tok::l_brace)) { + return sm.getFileOffset(sm.getFileLoc(tok.getLocation())); + } else { + return std::string::npos; + } + } while (tok.isNot(tok::eof)); + return std::string::npos; +} size_t cling::utils::getWrapPoint(std::string& source, const clang::LangOptions& LangOpts) {