From 236d76c4a9d180ad90cbba30d34236e19f37d609 Mon Sep 17 00:00:00 2001 From: Tim Shen Date: Sat, 19 Sep 2015 20:56:27 +0000 Subject: [PATCH] re PR libstdc++/67361 (std::regex_error::what() should say something about the error_code) PR libstdc++/67361 * include/bits/regex_error.h: Add __throw_regex_error that supports string. * include/bits/regex_automaton.h: Add more specific exception messages. * include/bits/regex_automaton.tcc: Likewise. * include/bits/regex_compiler.h: Likewise. * include/bits/regex_compiler.tcc: Likewise. * include/bits/regex_scanner.h: Likewise. * include/bits/regex_scanner.tcc: Likewise. From-SVN: r227936 --- libstdc++-v3/ChangeLog | 13 +++++ libstdc++-v3/include/bits/regex_automaton.h | 6 +- libstdc++-v3/include/bits/regex_automaton.tcc | 11 +++- libstdc++-v3/include/bits/regex_compiler.h | 12 ++-- libstdc++-v3/include/bits/regex_compiler.tcc | 37 +++++++++---- libstdc++-v3/include/bits/regex_error.h | 11 ++++ libstdc++-v3/include/bits/regex_scanner.tcc | 55 +++++++++++++------ 7 files changed, 110 insertions(+), 35 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 1540db24d48..e689d948859 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,16 @@ +2015-09-19 Tim Shen + + PR libstdc++/67361 + * include/bits/regex_error.h: Add __throw_regex_error that + supports string. + * include/bits/regex_automaton.h: Add more specific exception + messages. + * include/bits/regex_automaton.tcc: Likewise. + * include/bits/regex_compiler.h: Likewise. + * include/bits/regex_compiler.tcc: Likewise. + * include/bits/regex_scanner.h: Likewise. + * include/bits/regex_scanner.tcc: Likewise. + 2015-09-18 Jonathan Wakely * include/precompiled/extc++.h: Fix bootstrap error due to diff --git a/libstdc++-v3/include/bits/regex_automaton.h b/libstdc++-v3/include/bits/regex_automaton.h index b6ab3071ba7..1f672ee8105 100644 --- a/libstdc++-v3/include/bits/regex_automaton.h +++ b/libstdc++-v3/include/bits/regex_automaton.h @@ -327,7 +327,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { this->push_back(std::move(__s)); if (this->size() > _GLIBCXX_REGEX_STATE_LIMIT) - __throw_regex_error(regex_constants::error_space); + __throw_regex_error( + regex_constants::error_space, + "Number of NFA states exceeds limit. Please use shorter regex " + "string, or use smaller brace expression, or make " + "_GLIBCXX_REGEX_STATE_LIMIT larger."); return this->size()-1; } diff --git a/libstdc++-v3/include/bits/regex_automaton.tcc b/libstdc++-v3/include/bits/regex_automaton.tcc index f6f63a10d45..9bb116450ec 100644 --- a/libstdc++-v3/include/bits/regex_automaton.tcc +++ b/libstdc++-v3/include/bits/regex_automaton.tcc @@ -149,7 +149,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _NFA<_TraitsT>::_M_insert_backref(size_t __index) { if (this->_M_flags & regex_constants::__polynomial) - __throw_regex_error(regex_constants::error_complexity); + __throw_regex_error(regex_constants::error_complexity, + "Unexpected back-reference in polynomial mode."); // To figure out whether a backref is valid, a stack is used to store // unfinished sub-expressions. For example, when parsing // "(a(b)(c\\1(d)))" at '\\1', _M_subexpr_count is 3, indicating that 3 @@ -158,10 +159,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // _M_paren_stack is {1, 3}, for incomplete "(a.." and "(c..". At this // time, "\\2" is valid, but "\\1" and "\\3" are not. if (__index >= _M_subexpr_count) - __throw_regex_error(regex_constants::error_backref); + __throw_regex_error( + regex_constants::error_backref, + "Back-reference index exceeds current sub-expression count."); for (auto __it : this->_M_paren_stack) if (__index == __it) - __throw_regex_error(regex_constants::error_backref); + __throw_regex_error( + regex_constants::error_backref, + "Back-reference referred to an opened sub-expression."); this->_M_has_backref = true; _StateT __tmp(_S_opcode_backref); __tmp._M_backref_index = __index; diff --git a/libstdc++-v3/include/bits/regex_compiler.h b/libstdc++-v3/include/bits/regex_compiler.h index 07a9ed3555a..1f6348aed2e 100644 --- a/libstdc++-v3/include/bits/regex_compiler.h +++ b/libstdc++-v3/include/bits/regex_compiler.h @@ -392,7 +392,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto __st = _M_traits.lookup_collatename(__s.data(), __s.data() + __s.size()); if (__st.empty()) - __throw_regex_error(regex_constants::error_collate); + __throw_regex_error(regex_constants::error_collate, + "Invalid collate element."); _M_char_set.push_back(_M_translator._M_translate(__st[0])); _GLIBCXX_DEBUG_ONLY(_M_is_ready = false); return __st; @@ -404,7 +405,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto __st = _M_traits.lookup_collatename(__s.data(), __s.data() + __s.size()); if (__st.empty()) - __throw_regex_error(regex_constants::error_collate); + __throw_regex_error(regex_constants::error_collate, + "Invalid equivalence class."); __st = _M_traits.transform_primary(__st.data(), __st.data() + __st.size()); _M_equiv_set.push_back(__st); @@ -419,7 +421,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __s.data() + __s.size(), __icase); if (__mask == 0) - __throw_regex_error(regex_constants::error_ctype); + __throw_regex_error(regex_constants::error_collate, + "Invalid character class."); if (!__neg) _M_class_set |= __mask; else @@ -431,7 +434,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_make_range(_CharT __l, _CharT __r) { if (__l > __r) - __throw_regex_error(regex_constants::error_range); + __throw_regex_error(regex_constants::error_range, + "Invalid range in bracket expression."); _M_range_set.push_back(make_pair(_M_translator._M_transform(__l), _M_translator._M_transform(__r))); _GLIBCXX_DEBUG_ONLY(_M_is_ready = false); diff --git a/libstdc++-v3/include/bits/regex_compiler.tcc b/libstdc++-v3/include/bits/regex_compiler.tcc index 336a2e8133b..f7d52fc0d57 100644 --- a/libstdc++-v3/include/bits/regex_compiler.tcc +++ b/libstdc++-v3/include/bits/regex_compiler.tcc @@ -162,7 +162,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto __neg = _M_value[0] == 'n'; this->_M_disjunction(); if (!_M_match_token(_ScannerT::_S_token_subexpr_end)) - __throw_regex_error(regex_constants::error_paren); + __throw_regex_error(regex_constants::error_paren, + "Parenthesis is not closed."); auto __tmp = _M_pop(); __tmp._M_append(_M_nfa->_M_insert_accept()); _M_stack.push( @@ -184,7 +185,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto __init = [this, &__neg]() { if (_M_stack.empty()) - __throw_regex_error(regex_constants::error_badrepeat); + __throw_regex_error(regex_constants::error_badrepeat, + "Nothing to repeat before a quantifier."); __neg = __neg && _M_match_token(_ScannerT::_S_token_opt); }; if (_M_match_token(_ScannerT::_S_token_closure0)) @@ -220,9 +222,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else if (_M_match_token(_ScannerT::_S_token_interval_begin)) { if (_M_stack.empty()) - __throw_regex_error(regex_constants::error_badrepeat); + __throw_regex_error(regex_constants::error_badrepeat, + "Nothing to repeat before a quantifier."); if (!_M_match_token(_ScannerT::_S_token_dup_count)) - __throw_regex_error(regex_constants::error_badbrace); + __throw_regex_error(regex_constants::error_badbrace, + "Unexpected token in brace expression."); _StateSeqT __r(_M_pop()); _StateSeqT __e(*_M_nfa, _M_nfa->_M_insert_dummy()); long __min_rep = _M_cur_int_value(10); @@ -238,7 +242,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else __n = 0; if (!_M_match_token(_ScannerT::_S_token_interval_end)) - __throw_regex_error(regex_constants::error_brace); + __throw_regex_error(regex_constants::error_brace, + "Unexpected end of brace expression."); __neg = __neg && _M_match_token(_ScannerT::_S_token_opt); @@ -257,7 +262,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else { if (__n < 0) - __throw_regex_error(regex_constants::error_badbrace); + __throw_regex_error(regex_constants::error_badbrace, + "Invalid range in brace expression."); auto __end = _M_nfa->_M_insert_dummy(); // _M_alt is the "match more" branch, and _M_next is the // "match less" one. Switch _M_alt and _M_next of all created @@ -324,7 +330,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _StateSeqT __r(*_M_nfa, _M_nfa->_M_insert_dummy()); this->_M_disjunction(); if (!_M_match_token(_ScannerT::_S_token_subexpr_end)) - __throw_regex_error(regex_constants::error_paren); + __throw_regex_error(regex_constants::error_paren, + "Parenthesis is not closed."); __r._M_append(_M_pop()); _M_stack.push(__r); } @@ -333,7 +340,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _StateSeqT __r(*_M_nfa, _M_nfa->_M_insert_subexpr_begin()); this->_M_disjunction(); if (!_M_match_token(_ScannerT::_S_token_subexpr_end)) - __throw_regex_error(regex_constants::error_paren); + __throw_regex_error(regex_constants::error_paren, + "Parenthesis is not closed."); __r._M_append(_M_pop()); __r._M_append(_M_nfa->_M_insert_subexpr_end()); _M_stack.push(__r); @@ -474,7 +482,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if (_M_match_token(_ScannerT::_S_token_bracket_end)) return false; - __throw_regex_error(regex_constants::error_range); + __throw_regex_error( + regex_constants::error_range, + "Unexpected dash in bracket expression. For POSIX syntax, " + "a dash is not treated literally only when it is at " + "beginning or end."); } __last_char.first = true; __last_char.second = _M_value[0]; @@ -492,7 +504,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if (_M_scanner._M_get_token() != _ScannerT::_S_token_bracket_end) - __throw_regex_error(regex_constants::error_range); + __throw_regex_error( + regex_constants::error_range, + "Unexpected end of bracket expression."); __matcher._M_add_char(_M_value[0]); } } @@ -508,7 +522,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_ctype.is(_CtypeT::upper, _M_value[0])); else - __throw_regex_error(regex_constants::error_brack); + __throw_regex_error(regex_constants::error_brack, + "Unexpected character in bracket expression."); return true; } diff --git a/libstdc++-v3/include/bits/regex_error.h b/libstdc++-v3/include/bits/regex_error.h index 778edd5a097..be19fc10a3e 100644 --- a/libstdc++-v3/include/bits/regex_error.h +++ b/libstdc++-v3/include/bits/regex_error.h @@ -155,6 +155,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION regex_constants::error_type code() const { return _M_code; } + + private: + regex_error(regex_constants::error_type __ecode, const char* __what) + : std::runtime_error(__what), _M_code(__ecode) + { } + + friend void __throw_regex_error(regex_constants::error_type, const char*); }; //@} // group regex @@ -162,5 +169,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void __throw_regex_error(regex_constants::error_type __ecode); + inline void + __throw_regex_error(regex_constants::error_type __ecode, const char* __what) + { _GLIBCXX_THROW_OR_ABORT(regex_error(__ecode, __what)); } + _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/include/bits/regex_scanner.tcc b/libstdc++-v3/include/bits/regex_scanner.tcc index c158c65924a..7d24e0676b3 100644 --- a/libstdc++-v3/include/bits/regex_scanner.tcc +++ b/libstdc++-v3/include/bits/regex_scanner.tcc @@ -108,7 +108,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__c == '\\') { if (_M_current == _M_end) - __throw_regex_error(regex_constants::error_escape); + __throw_regex_error( + regex_constants::error_escape, + "Unexpected end of regex when escaping."); if (!_M_is_basic() || (*_M_current != '(' @@ -125,7 +127,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (_M_is_ecma() && *_M_current == '?') { if (++_M_current == _M_end) - __throw_regex_error(regex_constants::error_paren); + __throw_regex_error( + regex_constants::error_paren, + "Unexpected end of regex when in an open parenthesis."); if (*_M_current == ':') { @@ -145,7 +149,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_value.assign(1, 'n'); } else - __throw_regex_error(regex_constants::error_paren); + __throw_regex_error( + regex_constants::error_paren, + "Invalid special open parenthesis."); } else if (_M_flags & regex_constants::nosubs) _M_token = _S_token_subexpr_no_group_begin; @@ -204,14 +210,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_scan_in_bracket() { if (_M_current == _M_end) - __throw_regex_error(regex_constants::error_brack); + __throw_regex_error( + regex_constants::error_brack, + "Unexpected end of regex when in bracket expression."); auto __c = *_M_current++; if (__c == '[') { if (_M_current == _M_end) - __throw_regex_error(regex_constants::error_brack); + __throw_regex_error(regex_constants::error_brack, + "Unexpected character class open bracket."); if (*_M_current == '.') { @@ -261,7 +270,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_scan_in_brace() { if (_M_current == _M_end) - __throw_regex_error(regex_constants::error_brace); + __throw_regex_error( + regex_constants::error_brace, + "Unexpected end of regex when in brace expression."); auto __c = *_M_current++; @@ -285,7 +296,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ++_M_current; } else - __throw_regex_error(regex_constants::error_badbrace); + __throw_regex_error(regex_constants::error_badbrace, + "Unexpected character in brace expression."); } else if (__c == '}') { @@ -293,7 +305,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_token = _S_token_interval_end; } else - __throw_regex_error(regex_constants::error_badbrace); + __throw_regex_error(regex_constants::error_badbrace, + "Unexpected character in brace expression."); } template @@ -302,7 +315,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_eat_escape_ecma() { if (_M_current == _M_end) - __throw_regex_error(regex_constants::error_escape); + __throw_regex_error(regex_constants::error_escape, + "Unexpected end of regex when escaping."); auto __c = *_M_current++; auto __pos = _M_find_escape(_M_ctype.narrow(__c, '\0')); @@ -336,7 +350,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else if (__c == 'c') { if (_M_current == _M_end) - __throw_regex_error(regex_constants::error_escape); + __throw_regex_error( + regex_constants::error_escape, + "Unexpected end of regex when reading control code."); _M_token = _S_token_ord_char; _M_value.assign(1, *_M_current++); } @@ -347,7 +363,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { if (_M_current == _M_end || !_M_ctype.is(_CtypeT::xdigit, *_M_current)) - __throw_regex_error(regex_constants::error_escape); + __throw_regex_error( + regex_constants::error_escape, + "Unexpected end of regex when ascii character."); _M_value += *_M_current++; } _M_token = _S_token_hex_num; @@ -376,7 +394,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_eat_escape_posix() { if (_M_current == _M_end) - __throw_regex_error(regex_constants::error_escape); + __throw_regex_error(regex_constants::error_escape, + "Unexpected end of regex when escaping."); auto __c = *_M_current; auto __pos = std::strchr(_M_spec_char, _M_ctype.narrow(__c, '\0')); @@ -401,7 +420,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { #ifdef __STRICT_ANSI__ // POSIX says it is undefined to escape ordinary characters - __throw_regex_error(regex_constants::error_escape); + __throw_regex_error(regex_constants::error_escape, + "Unexpected escape character."); #else _M_token = _S_token_ord_char; _M_value.assign(1, __c); @@ -441,7 +461,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return; } else - __throw_regex_error(regex_constants::error_escape); + __throw_regex_error(regex_constants::error_escape, + "Unexpected escape character."); } // Eats a character class or throws an exception. @@ -460,9 +481,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION || *_M_current++ != ']') // skip ']' { if (__ch == ':') - __throw_regex_error(regex_constants::error_ctype); + __throw_regex_error(regex_constants::error_ctype, + "Unexpected end of character class."); else - __throw_regex_error(regex_constants::error_collate); + __throw_regex_error(regex_constants::error_collate, + "Unexpected end of character class."); } } -- 2.30.2