Index: libcxx/include/regex =================================================================== --- libcxx/include/regex +++ libcxx/include/regex @@ -32,7 +32,8 @@ extended = unspecified, awk = unspecified, grep = unspecified, - egrep = unspecified + egrep = unspecified, + multiline = unspecified }; constexpr syntax_option_type operator~(syntax_option_type f); @@ -142,6 +143,7 @@ static constexpr regex_constants::syntax_option_type awk = regex_constants::awk; static constexpr regex_constants::syntax_option_type grep = regex_constants::grep; static constexpr regex_constants::syntax_option_type egrep = regex_constants::egrep; + static constexpr regex_constants::syntax_option_type multiline = regex_constants::multiline; // construct/copy/destroy: basic_regex(); @@ -802,7 +804,9 @@ extended = 1 << 5, awk = 1 << 6, grep = 1 << 7, - egrep = 1 << 8 + egrep = 1 << 8, + // 1 << 9 may be used by ECMAScript + multiline = 1 << 10 }; inline _LIBCPP_CONSTEXPR @@ -1982,24 +1986,35 @@ // __l_anchor template -class __l_anchor +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR +bool __is_eol(_CharT c) +{ + return c == '\r' || c == '\n'; +} + +// LWG-2503 Added the multiline flag. In order to avoid an ABI break the +// __l_anchor has not been modified, it has been replaced with a new class. +template +class __l_anchor_multiline : public __owns_one_state<_CharT> { typedef __owns_one_state<_CharT> base; + bool __multiline; + public: typedef _VSTD::__state<_CharT> __state; _LIBCPP_INLINE_VISIBILITY - __l_anchor(__node<_CharT>* __s) - : base(__s) {} + __l_anchor_multiline(bool __multiline, __node<_CharT>* __s) + : base(__s), __multiline(__multiline) {} virtual void __exec(__state&) const; }; template void -__l_anchor<_CharT>::__exec(__state& __s) const +__l_anchor_multiline<_CharT>::__exec(__state& __s) const { if (__s.__at_first_ && __s.__current_ == __s.__first_ && !(__s.__flags_ & regex_constants::match_not_bol)) @@ -2007,6 +2022,13 @@ __s.__do_ = __state::__accept_but_not_consume; __s.__node_ = this->first(); } + else if (__multiline && + !__s.__at_first_ && + __is_eol(*_VSTD::prev(__s.__current_))) + { + __s.__do_ = __state::__accept_but_not_consume; + __s.__node_ = this->first(); + } else { __s.__do_ = __state::__reject; @@ -2016,25 +2038,29 @@ // __r_anchor +// LWG-2503 Added the multiline flag. In order to avoid an ABI break the +// __r_anchor has not been modified, it has been replaced with a new class. template -class __r_anchor +class __r_anchor_multiline : public __owns_one_state<_CharT> { typedef __owns_one_state<_CharT> base; + bool __multiline; + public: typedef _VSTD::__state<_CharT> __state; _LIBCPP_INLINE_VISIBILITY - __r_anchor(__node<_CharT>* __s) - : base(__s) {} + __r_anchor_multiline(bool __multiline, __node<_CharT>* __s) + : base(__s), __multiline(__multiline) {} virtual void __exec(__state&) const; }; template void -__r_anchor<_CharT>::__exec(__state& __s) const +__r_anchor_multiline<_CharT>::__exec(__state& __s) const { if (__s.__current_ == __s.__last_ && !(__s.__flags_ & regex_constants::match_not_eol)) @@ -2042,6 +2068,11 @@ __s.__do_ = __state::__accept_but_not_consume; __s.__node_ = this->first(); } + else if (__multiline && __is_eol(*__s.__current_)) + { + __s.__do_ = __state::__accept_but_not_consume; + __s.__node_ = this->first(); + } else { __s.__do_ = __state::__reject; @@ -2541,6 +2572,7 @@ static const regex_constants::syntax_option_type awk = regex_constants::awk; static const regex_constants::syntax_option_type grep = regex_constants::grep; static const regex_constants::syntax_option_type egrep = regex_constants::egrep; + static const regex_constants::syntax_option_type multiline = regex_constants::multiline; // construct/copy/destroy: _LIBCPP_INLINE_VISIBILITY @@ -2707,6 +2739,12 @@ _LIBCPP_INLINE_VISIBILITY unsigned __loop_count() const {return __loop_count_;} + _LIBCPP_INLINE_VISIBILITY + bool __use_multiline() const + { + return __get_grammar(__flags_) == ECMAScript && (__flags_ & multiline); + } + template void __init(_ForwardIterator __first, _ForwardIterator __last); @@ -4746,7 +4784,7 @@ void basic_regex<_CharT, _Traits>::__push_l_anchor() { - __end_->first() = new __l_anchor<_CharT>(__end_->first()); + __end_->first() = new __l_anchor_multiline<_CharT>(__use_multiline(), __end_->first()); __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first()); } @@ -4754,7 +4792,7 @@ void basic_regex<_CharT, _Traits>::__push_r_anchor() { - __end_->first() = new __r_anchor<_CharT>(__end_->first()); + __end_->first() = new __r_anchor_multiline<_CharT>(__use_multiline(), __end_->first()); __end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first()); } Index: libcxx/test/std/re/re.const/re.matchflag/match_multiline.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/re/re.const/re.matchflag/match_multiline.pass.cpp @@ -0,0 +1,272 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// multiline: +// Specifies that ^ shall match the beginning of a line and $ shall match +// the end of a line, if the ECMAScript engine is selected. + +#include +#include +#include "test_macros.h" + +static void search(const char* pat, std::regex_constants::syntax_option_type f, + const char* target, bool expected) +{ + std::regex re(pat, f); + std::cmatch m; + assert(std::regex_search(target, m, re) == expected); + + if(expected) { + assert(m.size() == 1); + assert(m.length(0) == 3); + assert(m.str(0) == "foo"); + } + else + { + assert(m.size() == 0); + } +} + +int main(int, char**) +{ + using std::regex_constants::ECMAScript; + using std::regex_constants::basic; + using std::regex_constants::extended; + using std::regex_constants::awk; + using std::regex_constants::grep; + using std::regex_constants::egrep; + using std::regex_constants::multiline; + + { + const char* pat = "^foo"; + const char* target = "foo"; + + search(pat, ECMAScript, target, true); + search(pat, basic, target, true); + search(pat, extended, target, true); + search(pat, awk, target, true); + search(pat, grep, target, true); + search(pat, egrep, target, true); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, true); + search(pat, extended | multiline, target, true); + search(pat, awk | multiline, target, true); + search(pat, grep | multiline, target, true); + search(pat, egrep | multiline, target, true); + } + { + const char* pat = "^foo"; + const char* target = "\nfoo"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + { + const char* pat = "^foo"; + const char* target = "bar\nfoo"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + + { + const char* pat = "foo$"; + const char* target = "foo"; + + search(pat, ECMAScript, target, true); + search(pat, basic, target, true); + search(pat, extended, target, true); + search(pat, awk, target, true); + search(pat, grep, target, true); + search(pat, egrep, target, true); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, true); + search(pat, extended | multiline, target, true); + search(pat, awk | multiline, target, true); + search(pat, grep | multiline, target, true); + search(pat, egrep | multiline, target, true); + } + { + const char* pat = "foo$"; + const char* target = "foo\n"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + { + const char* pat = "foo$"; + const char* target = "foo\nbar"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + + + { + const char* pat = "^foo"; + const char* target = "foo"; + + search(pat, ECMAScript, target, true); + search(pat, basic, target, true); + search(pat, extended, target, true); + search(pat, awk, target, true); + search(pat, grep, target, true); + search(pat, egrep, target, true); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, true); + search(pat, extended | multiline, target, true); + search(pat, awk | multiline, target, true); + search(pat, grep | multiline, target, true); + search(pat, egrep | multiline, target, true); + } + { + const char* pat = "^foo"; + const char* target = "\rfoo"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + { + const char* pat = "^foo"; + const char* target = "bar\rfoo"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + + { + const char* pat = "foo$"; + const char* target = "foo"; + + search(pat, ECMAScript, target, true); + search(pat, basic, target, true); + search(pat, extended, target, true); + search(pat, awk, target, true); + search(pat, grep, target, true); + search(pat, egrep, target, true); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, true); + search(pat, extended | multiline, target, true); + search(pat, awk | multiline, target, true); + search(pat, grep | multiline, target, true); + search(pat, egrep | multiline, target, true); + } + { + const char* pat = "foo$"; + const char* target = "foo\r"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + { + const char* pat = "foo$"; + const char* target = "foo\rbar"; + + search(pat, ECMAScript, target, false); + search(pat, basic, target, false); + search(pat, extended, target, false); + search(pat, awk, target, false); + search(pat, grep, target, false); + search(pat, egrep, target, false); + + search(pat, ECMAScript | multiline, target, true); + search(pat, basic | multiline, target, false); + search(pat, extended | multiline, target, false); + search(pat, awk | multiline, target, false); + search(pat, grep | multiline, target, false); + search(pat, egrep | multiline, target, false); + } + + return 0; +} Index: libcxx/test/std/re/re.const/re.synopt/syntax_option_type.pass.cpp =================================================================== --- libcxx/test/std/re/re.const/re.synopt/syntax_option_type.pass.cpp +++ libcxx/test/std/re/re.const/re.synopt/syntax_option_type.pass.cpp @@ -23,7 +23,8 @@ // extended = unspecified, // awk = unspecified, // grep = unspecified, -// egrep = unspecified +// egrep = unspecified, +// multiline = unspecified // }; // // } @@ -48,6 +49,7 @@ assert(std::regex_constants::awk != 0); assert(std::regex_constants::grep != 0); assert(std::regex_constants::egrep != 0); + assert(std::regex_constants::multiline != 0); assert((std::regex_constants::icase & std::regex_constants::nosubs) == 0); assert((std::regex_constants::icase & std::regex_constants::optimize) == 0); @@ -58,6 +60,7 @@ assert((std::regex_constants::icase & std::regex_constants::awk) == 0); assert((std::regex_constants::icase & std::regex_constants::grep) == 0); assert((std::regex_constants::icase & std::regex_constants::egrep) == 0); + assert((std::regex_constants::icase & std::regex_constants::multiline) == 0); assert((std::regex_constants::nosubs & std::regex_constants::optimize) == 0); assert((std::regex_constants::nosubs & std::regex_constants::collate) == 0); @@ -67,6 +70,7 @@ assert((std::regex_constants::nosubs & std::regex_constants::awk) == 0); assert((std::regex_constants::nosubs & std::regex_constants::grep) == 0); assert((std::regex_constants::nosubs & std::regex_constants::egrep) == 0); + assert((std::regex_constants::nosubs & std::regex_constants::multiline) == 0); assert((std::regex_constants::optimize & std::regex_constants::collate) == 0); assert((std::regex_constants::optimize & std::regex_constants::ECMAScript) == 0); @@ -75,6 +79,7 @@ assert((std::regex_constants::optimize & std::regex_constants::awk) == 0); assert((std::regex_constants::optimize & std::regex_constants::grep) == 0); assert((std::regex_constants::optimize & std::regex_constants::egrep) == 0); + assert((std::regex_constants::optimize & std::regex_constants::multiline) == 0); assert((std::regex_constants::collate & std::regex_constants::ECMAScript) == 0); assert((std::regex_constants::collate & std::regex_constants::basic) == 0); @@ -82,26 +87,34 @@ assert((std::regex_constants::collate & std::regex_constants::awk) == 0); assert((std::regex_constants::collate & std::regex_constants::grep) == 0); assert((std::regex_constants::collate & std::regex_constants::egrep) == 0); + assert((std::regex_constants::collate & std::regex_constants::multiline) == 0); assert((std::regex_constants::ECMAScript & std::regex_constants::basic) == 0); assert((std::regex_constants::ECMAScript & std::regex_constants::extended) == 0); assert((std::regex_constants::ECMAScript & std::regex_constants::awk) == 0); assert((std::regex_constants::ECMAScript & std::regex_constants::grep) == 0); assert((std::regex_constants::ECMAScript & std::regex_constants::egrep) == 0); + assert((std::regex_constants::ECMAScript & std::regex_constants::multiline) == 0); assert((std::regex_constants::basic & std::regex_constants::extended) == 0); assert((std::regex_constants::basic & std::regex_constants::awk) == 0); assert((std::regex_constants::basic & std::regex_constants::grep) == 0); assert((std::regex_constants::basic & std::regex_constants::egrep) == 0); + assert((std::regex_constants::basic & std::regex_constants::multiline) == 0); assert((std::regex_constants::extended & std::regex_constants::awk) == 0); assert((std::regex_constants::extended & std::regex_constants::grep) == 0); assert((std::regex_constants::extended & std::regex_constants::egrep) == 0); + assert((std::regex_constants::extended & std::regex_constants::multiline) == 0); assert((std::regex_constants::awk & std::regex_constants::grep) == 0); assert((std::regex_constants::awk & std::regex_constants::egrep) == 0); + assert((std::regex_constants::awk & std::regex_constants::multiline) == 0); assert((std::regex_constants::grep & std::regex_constants::egrep) == 0); + assert((std::regex_constants::grep & std::regex_constants::multiline) == 0); + + assert((std::regex_constants::egrep & std::regex_constants::multiline) == 0); assert((std::regex_constants::icase | std::regex_constants::nosubs) != 0); assert((std::regex_constants::icase ^ std::regex_constants::nosubs) != 0); Index: libcxx/www/cxx1z_status.html =================================================================== --- libcxx/www/cxx1z_status.html +++ libcxx/www/cxx1z_status.html @@ -371,7 +371,7 @@ 2460LWG issue 2408 and value categoriesIssaquahComplete 2468Self-move-assignment of library typesIssaquah 2475Allow overwriting of std::basic_string terminator with charT() to allow cleaner interoperation with legacy APIsIssaquahComplete - 2503multiline option should be added to syntax_option_typeIssaquah + 2503multiline option should be added to syntax_option_typeIssaquahComplete 2510Tag types should not be DefaultConstructibleIssaquahComplete 2514Type traits must not be finalIssaquahComplete 2518[fund.ts.v2] Non-member swap for propagate_const should call member swapIssaquahComplete @@ -503,7 +503,7 @@ -

Last Updated: 3-Jul-2019

+

Last Updated: 17-Nov-2020