Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -267,8 +267,10 @@ } auto Filename = FileEntry->getName(); - llvm::Regex RE(RegExp); - return RE.match(Filename); + auto RE = llvm::Regex::compile(RegExp); + // Note that this does not handle any errors from regex compilation, so + // it will crash on broken patterns when asserts are enabled. + return RE && RE->match(Filename); } /// \brief Matches declarations. @@ -2178,8 +2180,10 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) { assert(!RegExp.empty()); std::string FullNameString = "::" + Node.getQualifiedNameAsString(); - llvm::Regex RE(RegExp); - return RE.match(FullNameString); + auto RE = llvm::Regex::compile(RegExp); + // Note that this does not handle any errors from regex compilation, so + // it will crash on broken patterns when asserts are enabled. + return RE && RE->match(FullNameString); } /// \brief Matches overloaded operator names. @@ -2550,8 +2554,10 @@ AST_MATCHER_P(ObjCMessageExpr, matchesSelector, std::string, RegExp) { assert(!RegExp.empty()); std::string SelectorString = Node.getSelector().getAsString(); - llvm::Regex RE(RegExp); - return RE.match(SelectorString); + auto RE = llvm::Regex::compile(RegExp); + // Note that this does not handle any errors from regex compilation, so + // it will crash on broken patterns when asserts are enabled. + return RE && RE->match(SelectorString); } /// \brief Matches when the selector is the empty selector Index: include/clang/Frontend/VerifyDiagnosticConsumer.h =================================================================== --- include/clang/Frontend/VerifyDiagnosticConsumer.h +++ include/clang/Frontend/VerifyDiagnosticConsumer.h @@ -165,6 +165,11 @@ // Returns true if directive text is valid. // Otherwise returns false and populates E. + // + // This should only be called once: after calling, the object's + // internal representation for isValid may be in an indeterminate + // state, where it is only safe to destruct (although the Directive + // object itself must be safe to use if isValid returns true). virtual bool isValid(std::string &Error) = 0; // Returns true on match. Index: lib/Driver/Multilib.cpp =================================================================== --- lib/Driver/Multilib.cpp +++ lib/Driver/Multilib.cpp @@ -214,16 +214,15 @@ } MultilibSet &MultilibSet::FilterOut(const char *Regex) { - llvm::Regex R(Regex); + auto R = llvm::Regex::compile(Regex); + if (!R) { #ifndef NDEBUG - std::string Error; - if (!R.isValid(Error)) { - llvm::errs() << Error; + llvm::errs() << toString(R.takeError()); +#endif llvm_unreachable("Invalid regex!"); } -#endif - filterInPlace([&R](const Multilib &M) { return R.match(M.gccSuffix()); }, + filterInPlace([&R](const Multilib &M) { return R->match(M.gccSuffix()); }, Multilibs); return *this; } Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -69,8 +69,11 @@ bool BinPackInconclusiveFunctions) : Style(Style), Keywords(Keywords), SourceMgr(SourceMgr), Whitespaces(Whitespaces), Encoding(Encoding), - BinPackInconclusiveFunctions(BinPackInconclusiveFunctions), - CommentPragmasRegex(Style.CommentPragmas) {} + BinPackInconclusiveFunctions(BinPackInconclusiveFunctions) { + if (auto RegexOrError = llvm::Regex::compile(Style.CommentPragmas)) { + CommentPragmasRegex = std::move(*RegexOrError); + } +} LineState ContinuationIndenter::getInitialState(unsigned FirstIndent, const AnnotatedLine *Line, Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -1336,8 +1336,11 @@ IncludeCategoryManager(const FormatStyle &Style, StringRef FileName) : Style(Style), FileName(FileName) { FileStem = llvm::sys::path::stem(FileName); - for (const auto &Category : Style.IncludeCategories) - CategoryRegexs.emplace_back(Category.Regex); + for (const auto &Category : Style.IncludeCategories) { + if (auto RegexOrError = llvm::Regex::compile(Category.Regex)) { + CategoryRegexs.emplace_back(std::move(*RegexOrError)); + } + } IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") || FileName.endswith(".cpp") || FileName.endswith(".c++") || FileName.endswith(".cxx") || FileName.endswith(".m") || @@ -1366,9 +1369,11 @@ StringRef HeaderStem = llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1)); if (FileStem.startswith(HeaderStem)) { - llvm::Regex MainIncludeRegex( - (HeaderStem + Style.IncludeIsMainRegex).str()); - if (MainIncludeRegex.match(FileStem)) + auto MainIncludeRegex = + llvm::Regex::compile((HeaderStem + Style.IncludeIsMainRegex).str()); + // Note that this does not handle the error case. In a build with + // asserts enabled, an invalid pattern will cause a crash. + if (MainIncludeRegex && MainIncludeRegex->match(FileStem)) return true; } return false; @@ -1393,7 +1398,11 @@ unsigned *Cursor) { unsigned Prev = 0; unsigned SearchFrom = 0; - llvm::Regex IncludeRegex(IncludeRegexPattern); + llvm::Regex IncludeRegex; + // Note that this does not handle the error case. In a build with asserts + // enabled, an invalid IncludeRegexPattern will cause a crash. + if (auto RegexOrError = llvm::Regex::compile(IncludeRegexPattern)) + IncludeRegex = std::move(*RegexOrError); SmallVector Matches; SmallVector IncludesInBlock; @@ -1506,8 +1515,12 @@ namespace { inline bool isHeaderInsertion(const tooling::Replacement &Replace) { + auto RegexOrError = llvm::Regex::compile(IncludeRegexPattern); + // Note that this does not handle the error case. In a build with asserts + // enabled, an invalid IncludeRegexPattern will cause a crash. + if (!RegexOrError) return false; return Replace.getOffset() == UINT_MAX && Replace.getLength() == 0 && - llvm::Regex(IncludeRegexPattern).match(Replace.getReplacementText()); + RegexOrError->match(Replace.getReplacementText()); } inline bool isHeaderDeletion(const tooling::Replacement &Replace) { @@ -1658,8 +1671,11 @@ if (HeaderInsertions.empty() && HeadersToDelete.empty()) return Replaces; - llvm::Regex IncludeRegex(IncludeRegexPattern); - llvm::Regex DefineRegex(R"(^[\t\ ]*#[\t\ ]*define[\t\ ]*[^\\]*$)"); + llvm::Regex IncludeRegex; + // Note that this does not handle the error case. In a build with asserts + // enabled, an invalid IncludeRegexPattern will cause a crash. + if (auto RegexOrError = llvm::Regex::compile(IncludeRegexPattern)) + IncludeRegex = std::move(*RegexOrError); SmallVector Matches; StringRef FileName = Replaces.begin()->getFilePath(); Index: lib/Format/FormatTokenLexer.cpp =================================================================== --- lib/Format/FormatTokenLexer.cpp +++ lib/Format/FormatTokenLexer.cpp @@ -30,8 +30,13 @@ Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID), Style(Style), IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0), - FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin), - MacroBlockEndRegex(Style.MacroBlockEnd) { + FormattingDisabled(false) { + if (auto RegexOrError = llvm::Regex::compile(Style.MacroBlockBegin)) { + MacroBlockBeginRegex = std::move(*RegexOrError); + } + if (auto RegexOrError = llvm::Regex::compile(Style.MacroBlockEnd)) { + MacroBlockEndRegex = std::move(*RegexOrError); + } Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr, getFormattingLangOpts(Style))); Lex->SetKeepWhitespaceMode(true); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -338,13 +338,13 @@ Arg *RpassArg) { StringRef Val = RpassArg->getValue(); std::string RegexError; - std::shared_ptr Pattern = std::make_shared(Val); - if (!Pattern->isValid(RegexError)) { + auto RegexOrError = llvm::Regex::compile(Val); + if (!RegexOrError) { Diags.Report(diag::err_drv_optimization_remark_pattern) - << RegexError << RpassArg->getAsString(Args); - Pattern.reset(); + << toString(RegexOrError.takeError()) << RpassArg->getAsString(Args); + return nullptr; } - return Pattern; + return std::make_shared(std::move(*RegexOrError)); } static bool parseDiagnosticLevelMask(StringRef FlagName, Index: lib/Frontend/VerifyDiagnosticConsumer.cpp =================================================================== --- lib/Frontend/VerifyDiagnosticConsumer.cpp +++ lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -184,10 +184,19 @@ bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max, StringRef RegexStr) : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max), - Regex(RegexStr) { } + Err(llvm::Error::success()) { + if (auto RegexOrError = llvm::Regex::compile(RegexStr)) { + Regex = std::move(*RegexOrError); + } else { + Err = RegexOrError.takeError(); + } + } bool isValid(std::string &Error) override { - return Regex.isValid(Error); + if (!Err) + return true; + Error = toString(std::move(Err)); + return false; } bool match(StringRef S) override { @@ -196,6 +205,7 @@ private: llvm::Regex Regex; + llvm::Error Err; }; class ParseHelper Index: tools/driver/driver.cpp =================================================================== --- tools/driver/driver.cpp +++ tools/driver/driver.cpp @@ -120,7 +120,8 @@ // Ignore end-of-line response file markers if (Args[i] == nullptr) continue; - std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]); + auto RE = llvm::Regex::compile(MatchPattern); + std::string Repl = RE ? RE->sub(ReplPattern, Args[i]) : Args[i]; if (Repl != Args[i]) { OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n"; Index: unittests/ASTMatchers/ASTMatchersNodeTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -1521,9 +1521,9 @@ EXPECT_TRUE(matchesObjC( Objc1String, objcMessageExpr(matchesSelector("cont*")))); - EXPECT_FALSE(matchesObjC( + EXPECT_TRUE(matchesObjC( Objc1String, - objcMessageExpr(matchesSelector("?cont*")))); + objcMessageExpr(matchesSelector("-?cont*")))); EXPECT_TRUE(notMatchesObjC( Objc1String, objcMessageExpr(hasSelector("contents"), hasNullSelector())));