Summary:
GCC has the temerity to insinuate that my code has out-of-array-bounds access. After cross-checking with clang and ubsan, reviewing the code, and running constexpr tests (for which out-of-range errors are caught at compile time), I can say with pretty high confidence that this is an instance of GCC#61971 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61971). Basically, the gcc-4 series is known to issue spurious -Warray-bounds warnings. The "fix" is to route internal accesses to some helper functions, for which -Warray-bounds has been suppressed.
User code that accesses elements with operator[] will still warn on out-of-bounds access. If this is a problem in practice, we can suppress the warning there, too. Trying this for now since it is less likely to hide real problems.
Reviewed By: yfeldblum
Differential Revision:
D4317305
fbshipit-source-id:
7bf92f993ac1a29631463c582c1b64d76f755181
using FixedStringBase = FixedStringBase_<>;
using FixedStringBase = FixedStringBase_<>;
-template <class Char, std::size_t N>
-constexpr std::size_t size(const Char (&)[N]) noexcept {
- return N - 1u;
-}
-
-template <class Char, std::size_t N>
-constexpr std::size_t size(const BasicFixedString<Char, N>& s) noexcept {
- return s.size();
-}
-
// Intentionally NOT constexpr. By making this not constexpr, we make
// checkOverflow below ill-formed in a constexpr context when the condition
// it's testing for fails. In this way, precondition violations are reported
// Intentionally NOT constexpr. By making this not constexpr, we make
// checkOverflow below ill-formed in a constexpr context when the condition
// it's testing for fails. In this way, precondition violations are reported
enum class Cmp : int { LT = -1, EQ = 0, GT = 1 };
enum class Cmp : int { LT = -1, EQ = 0, GT = 1 };
+// Rather annoyingly, GCC's -Warray-bounds warning issues false positives for
+// this code. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61971
+#if defined(__GNUC__) && !defined(__CLANG__) && __GNUC__ <= 4
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#endif
+
template <class Left, class Right>
constexpr Cmp compare_(
const Left& left,
template <class Left, class Right>
constexpr Cmp compare_(
const Left& left,
}
template <class Char, class Left, class Right>
}
template <class Char, class Left, class Right>
-constexpr Char
-char_at_(const Left& left, const Right& right, std::size_t i) noexcept {
- return i < fixedstring::size(left)
+constexpr Char char_at_(
+ const Left& left,
+ std::size_t left_count,
+ const Right& right,
+ std::size_t right_count,
+ std::size_t i) noexcept {
+ return i < left_count
- : i < (fixedstring::size(left) + fixedstring::size(right))
- ? right[i - fixedstring::size(left)]
- : Char(0);
+ : i < (left_count + right_count) ? right[i - left_count] : Char(0);
}
template <class Char, class Left, class Right>
constexpr Char char_at_(
const Left& left,
}
template <class Char, class Left, class Right>
constexpr Char char_at_(
const Left& left,
std::size_t left_pos,
std::size_t left_count,
const Right& right,
std::size_t left_pos,
std::size_t left_count,
const Right& right,
std::size_t i) noexcept {
return i < left_pos
? left[i]
std::size_t i) noexcept {
return i < left_pos
? left[i]
- : (i < right_count + left_pos
- ? right[i - left_pos + right_pos]
- : (i < fixedstring::size(left) - left_count + right_count
- ? left[i - right_count + left_count]
- : Char(0)));
+ : (i < right_count + left_pos ? right[i - left_pos + right_pos]
+ : (i < left_size - left_count + right_count
+ ? left[i - right_count + left_count]
+ : Char(0)));
}
template <class Left, class Right>
}
template <class Left, class Right>
template <class Left, class Right>
constexpr std::size_t find_(
const Left& left,
template <class Left, class Right>
constexpr std::size_t find_(
const Left& left,
const Right& right,
std::size_t pos,
std::size_t count) noexcept {
const Right& right,
std::size_t pos,
std::size_t count) noexcept {
- return find_at_(left, right, pos, count)
- ? pos
- : fixedstring::size(left) <= pos + count
+ return find_at_(left, right, pos, count) ? pos
+ : left_size <= pos + count
- : find_(left, right, pos + 1u, count);
+ : find_(left, left_size, right, pos + 1u, count);
}
template <class Left, class Right>
}
template <class Left, class Right>
template <class Left, class Right>
constexpr std::size_t find_first_of_(
const Left& left,
template <class Left, class Right>
constexpr std::size_t find_first_of_(
const Left& left,
const Right& right,
std::size_t pos,
std::size_t count) noexcept {
const Right& right,
std::size_t pos,
std::size_t count) noexcept {
- return find_one_of_at_(left[pos], right, count)
- ? pos
- : fixedstring::size(left) <= pos + 1u
+ return find_one_of_at_(left[pos], right, count) ? pos
+ : left_size <= pos + 1u
- : find_first_of_(left, right, pos + 1u, count);
+ : find_first_of_(left, left_size, right, pos + 1u, count);
}
template <class Left, class Right>
constexpr std::size_t find_first_not_of_(
const Left& left,
}
template <class Left, class Right>
constexpr std::size_t find_first_not_of_(
const Left& left,
const Right& right,
std::size_t pos,
std::size_t count) noexcept {
const Right& right,
std::size_t pos,
std::size_t count) noexcept {
- return !find_one_of_at_(left[pos], right, count)
- ? pos
- : fixedstring::size(left) <= pos + 1u
+ return !find_one_of_at_(left[pos], right, count) ? pos
+ : left_size <= pos + 1u
- : find_first_not_of_(left, right, pos + 1u, count);
+ : find_first_not_of_(left, left_size, right, pos + 1u, count);
}
template <class Left, class Right>
}
template <class Left, class Right>
template <class Char, class Left, class Right, std::size_t... Is>
static constexpr BasicFixedString<Char, sizeof...(Is)> concat_(
const Left& left,
template <class Char, class Left, class Right, std::size_t... Is>
static constexpr BasicFixedString<Char, sizeof...(Is)> concat_(
const Left& left,
+ std::size_t left_count,
+ std::size_t right_count,
std::index_sequence<Is...> is) noexcept {
std::index_sequence<Is...> is) noexcept {
- return {left, right, is};
+ return {left, left_count, right, right_count, is};
}
template <class Char, class Left, class Right, std::size_t... Is>
static constexpr BasicFixedString<Char, sizeof...(Is)> replace_(
const Left& left,
}
template <class Char, class Left, class Right, std::size_t... Is>
static constexpr BasicFixedString<Char, sizeof...(Is)> replace_(
const Left& left,
std::size_t left_pos,
std::size_t left_count,
const Right& right,
std::size_t right_pos,
std::size_t right_count,
std::index_sequence<Is...> is) noexcept {
std::size_t left_pos,
std::size_t left_count,
const Right& right,
std::size_t right_pos,
std::size_t right_count,
std::index_sequence<Is...> is) noexcept {
- return {left, left_pos, left_count, right, right_pos, right_count, is};
+ return {left,
+ left_size,
+ left_pos,
+ left_count,
+ right,
+ right_pos,
+ right_count,
+ is};
+ }
+
+ template <class Char, std::size_t N>
+ static constexpr const Char (
+ &data_(const BasicFixedString<Char, N>& that) noexcept)[N + 1u] {
+ return that.data_;
+#if defined(__GNUC__) && !defined(__CLANG__) && __GNUC__ <= 4
+#pragma GCC diagnostic pop
+#endif
+
template <class T>
FOLLY_CPP14_CONSTEXPR void constexpr_swap(T& a, T& b) noexcept(
noexcept(a = T(std::move(a)))) {
template <class T>
FOLLY_CPP14_CONSTEXPR void constexpr_swap(T& a, T& b) noexcept(
noexcept(a = T(std::move(a)))) {
template <class Left, class Right, std::size_t... Is>
constexpr BasicFixedString(
const Left& left,
template <class Left, class Right, std::size_t... Is>
constexpr BasicFixedString(
const Left& left,
+ std::size_t right_size,
std::index_sequence<Is...>) noexcept
std::index_sequence<Is...>) noexcept
- : data_{detail::fixedstring::char_at_<Char>(left, right, Is)..., Char(0)},
- size_{detail::fixedstring::size(left) +
- detail::fixedstring::size(right)} {}
+ : data_{detail::fixedstring::char_at_<Char>(
+ left,
+ left_size,
+ right,
+ right_size,
+ Is)...,
+ Char(0)},
+ size_{left_size + right_size} {}
// Replace constructor
template <class Left, class Right, std::size_t... Is>
constexpr BasicFixedString(
const Left& left,
// Replace constructor
template <class Left, class Right, std::size_t... Is>
constexpr BasicFixedString(
const Left& left,
std::size_t left_pos,
std::size_t left_count,
const Right& right,
std::size_t left_pos,
std::size_t left_count,
const Right& right,
std::index_sequence<Is...>) noexcept
: data_{detail::fixedstring::char_at_<Char>(
left,
std::index_sequence<Is...>) noexcept
: data_{detail::fixedstring::char_at_<Char>(
left,
left_pos,
left_count,
right,
left_pos,
left_count,
right,
right_count,
Is)...,
Char(0)},
right_count,
Is)...,
Char(0)},
- size_{detail::fixedstring::size(left) - left_count + right_count} {}
+ size_{left_size - left_count + right_count} {}
public:
using size_type = std::size_t;
public:
using size_type = std::size_t;
count = detail::fixedstring::checkOverflowOrNpos(count, that.size_ - pos);
detail::fixedstring::checkOverflow(count, N - size_);
for (std::size_t i = 0u; i < count; ++i)
count = detail::fixedstring::checkOverflowOrNpos(count, that.size_ - pos);
detail::fixedstring::checkOverflow(count, N - size_);
for (std::size_t i = 0u; i < count; ++i)
- data_[size_ + i] = that[pos + i];
+ data_[size_ + i] = that.data_[pos + i];
size_ += count;
data_[size_] = Char(0);
return *this;
size_ += count;
data_[size_] = Char(0);
return *this;
std::size_t that_pos,
std::size_t that_count) const noexcept(false) {
return static_cast<int>(detail::fixedstring::compare_(
std::size_t that_pos,
std::size_t that_count) const noexcept(false) {
return static_cast<int>(detail::fixedstring::compare_(
detail::fixedstring::checkOverflow(this_pos, size_),
detail::fixedstring::checkOverflow(this_count, size_ - this_pos) +
this_pos,
detail::fixedstring::checkOverflow(this_pos, size_),
detail::fixedstring::checkOverflow(this_count, size_ - this_pos) +
this_pos,
detail::fixedstring::checkOverflow(that_pos, that.size_),
detail::fixedstring::checkOverflow(that_count, that.size_ - that_pos) +
that_pos));
detail::fixedstring::checkOverflow(that_pos, that.size_),
detail::fixedstring::checkOverflow(that_count, that.size_ - that_pos) +
that_pos));
const Char* that,
std::size_t that_count) const noexcept(false) {
return static_cast<int>(detail::fixedstring::compare_(
const Char* that,
std::size_t that_count) const noexcept(false) {
return static_cast<int>(detail::fixedstring::compare_(
detail::fixedstring::checkOverflow(this_pos, size_),
detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos) +
this_pos,
detail::fixedstring::checkOverflow(this_pos, size_),
detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos) +
this_pos,
const Char* that,
std::size_t that_count) noexcept(false) {
return *this = detail::fixedstring::Helper::replace_<Char>(
const Char* that,
std::size_t that_count) noexcept(false) {
return *this = detail::fixedstring::Helper::replace_<Char>(
detail::fixedstring::checkOverflow(this_pos, size_),
detail::fixedstring::checkOverflowOrNpos(
this_count, size_ - this_pos),
detail::fixedstring::checkOverflow(this_pos, size_),
detail::fixedstring::checkOverflowOrNpos(
this_count, size_ - this_pos),
std::size_t that_pos,
std::size_t that_count) const noexcept(false) {
return detail::fixedstring::Helper::replace_<Char>(
std::size_t that_pos,
std::size_t that_count) const noexcept(false) {
return detail::fixedstring::Helper::replace_<Char>(
detail::fixedstring::checkOverflow(this_pos, size_),
detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos),
detail::fixedstring::checkOverflow(this_pos, size_),
detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos),
detail::fixedstring::checkOverflow(that_pos, that.size_),
detail::fixedstring::checkOverflowOrNpos(
that_count, that.size_ - that_pos),
detail::fixedstring::checkOverflow(that_pos, that.size_),
detail::fixedstring::checkOverflowOrNpos(
that_count, that.size_ - that_pos),
std::size_t that_pos,
std::size_t that_count) const noexcept(false) {
return detail::fixedstring::Helper::replace_<Char>(
std::size_t that_pos,
std::size_t that_count) const noexcept(false) {
return detail::fixedstring::Helper::replace_<Char>(
detail::fixedstring::checkOverflow(this_pos, size_),
detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos),
detail::fixedstring::checkNullTerminated(that),
detail::fixedstring::checkOverflow(this_pos, size_),
detail::fixedstring::checkOverflowOrNpos(this_count, size_ - this_pos),
detail::fixedstring::checkNullTerminated(that),
const BasicFixedString<Char, M>& that,
std::size_t pos) const noexcept(false) {
return that.size_ <= size_ - detail::fixedstring::checkOverflow(pos, size_)
const BasicFixedString<Char, M>& that,
std::size_t pos) const noexcept(false) {
return that.size_ <= size_ - detail::fixedstring::checkOverflow(pos, size_)
- ? detail::fixedstring::find_(*this, that, pos, that.size_)
+ ? detail::fixedstring::find_(data_, size_, that.data_, pos, that.size_)
std::size_t pos,
std::size_t count) const noexcept(false) {
return count <= size_ - detail::fixedstring::checkOverflow(pos, size_)
std::size_t pos,
std::size_t count) const noexcept(false) {
return count <= size_ - detail::fixedstring::checkOverflow(pos, size_)
- ? detail::fixedstring::find_(*this, that, pos, count)
+ ? detail::fixedstring::find_(data_, size_, that, pos, count)
using A = const Char[1u];
return 0u == size_ - detail::fixedstring::checkOverflow(pos, size_)
? npos
using A = const Char[1u];
return 0u == size_ - detail::fixedstring::checkOverflow(pos, size_)
? npos
- : detail::fixedstring::find_(*this, A{ch}, pos, 1u);
+ : detail::fixedstring::find_(data_, size_, A{ch}, pos, 1u);
}
/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
}
/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
std::size_t pos) const noexcept(false) {
return that.size_ <= size_
? detail::fixedstring::rfind_(
std::size_t pos) const noexcept(false) {
return that.size_ <= size_
? detail::fixedstring::rfind_(
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_),
size_ - that.size_),
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_),
size_ - that.size_),
std::size_t count) const noexcept(false) {
return count <= size_
? detail::fixedstring::rfind_(
std::size_t count) const noexcept(false) {
return count <= size_
? detail::fixedstring::rfind_(
that,
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_),
that,
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_),
return 0u == size_
? npos
: detail::fixedstring::rfind_(
return 0u == size_
? npos
: detail::fixedstring::rfind_(
A{ch},
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
A{ch},
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
std::size_t pos) const noexcept(false) {
return size_ == detail::fixedstring::checkOverflow(pos, size_)
? npos
std::size_t pos) const noexcept(false) {
return size_ == detail::fixedstring::checkOverflow(pos, size_)
? npos
- : detail::fixedstring::find_first_of_(*this, that, pos, that.size_);
+ : detail::fixedstring::find_first_of_(
+ data_, size_, that.data_, pos, that.size_);
std::size_t count) const noexcept(false) {
return size_ == detail::fixedstring::checkOverflow(pos, size_)
? npos
std::size_t count) const noexcept(false) {
return size_ == detail::fixedstring::checkOverflow(pos, size_)
? npos
- : detail::fixedstring::find_first_of_(*this, that, pos, count);
+ : detail::fixedstring::find_first_of_(data_, size_, that, pos, count);
using A = const Char[1u];
return size_ == detail::fixedstring::checkOverflow(pos, size_)
? npos
using A = const Char[1u];
return size_ == detail::fixedstring::checkOverflow(pos, size_)
? npos
- : detail::fixedstring::find_first_of_(*this, A{ch}, pos, 1u);
+ : detail::fixedstring::find_first_of_(data_, size_, A{ch}, pos, 1u);
}
/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
}
/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
std::size_t pos) const noexcept(false) {
return size_ == detail::fixedstring::checkOverflow(pos, size_)
? npos
std::size_t pos) const noexcept(false) {
return size_ == detail::fixedstring::checkOverflow(pos, size_)
? npos
- : detail::fixedstring::find_first_not_of_(*this, that, pos, that.size_);
+ : detail::fixedstring::find_first_not_of_(
+ data_, size_, that.data_, pos, that.size_);
std::size_t count) const noexcept(false) {
return size_ == detail::fixedstring::checkOverflow(pos, size_)
? npos
std::size_t count) const noexcept(false) {
return size_ == detail::fixedstring::checkOverflow(pos, size_)
? npos
- : detail::fixedstring::find_first_not_of_(*this, that, pos, count);
+ : detail::fixedstring::find_first_not_of_(
+ data_, size_, that, pos, count);
noexcept(false) {
using A = const Char[1u];
return 1u <= size_ - detail::fixedstring::checkOverflow(pos, size_)
noexcept(false) {
using A = const Char[1u];
return 1u <= size_ - detail::fixedstring::checkOverflow(pos, size_)
- ? detail::fixedstring::find_first_not_of_(*this, A{ch}, pos, 1u)
+ ? detail::fixedstring::find_first_not_of_(data_, size_, A{ch}, pos, 1u)
return 0u == size_
? npos
: detail::fixedstring::find_last_of_(
return 0u == size_
? npos
: detail::fixedstring::find_last_of_(
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
that.size_);
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
that.size_);
return 0u == size_
? npos
: detail::fixedstring::find_last_of_(
return 0u == size_
? npos
: detail::fixedstring::find_last_of_(
that,
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
that,
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
return 0u == size_
? npos
: detail::fixedstring::find_last_of_(
return 0u == size_
? npos
: detail::fixedstring::find_last_of_(
A{ch},
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
A{ch},
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
return 0u == size_
? npos
: detail::fixedstring::find_last_not_of_(
return 0u == size_
? npos
: detail::fixedstring::find_last_not_of_(
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
that.size_);
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
that.size_);
return 0u == size_
? npos
: detail::fixedstring::find_last_not_of_(
return 0u == size_
? npos
: detail::fixedstring::find_last_not_of_(
that,
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
that,
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
return 0u == size_
? npos
: detail::fixedstring::find_last_not_of_(
return 0u == size_
? npos
: detail::fixedstring::find_last_not_of_(
A{ch},
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
A{ch},
folly::constexpr_min(
detail::fixedstring::checkOverflow(pos, size_), size_ - 1u),
const Char* a,
const BasicFixedString& b) noexcept {
return detail::fixedstring::equal_(
const Char* a,
const BasicFixedString& b) noexcept {
return detail::fixedstring::equal_(
- a, folly::constexpr_strlen(a), b, b.size());
+ a, folly::constexpr_strlen(a), b.data_, b.size_);
const BasicFixedString& b) noexcept {
return detail::fixedstring::Cmp::LT ==
detail::fixedstring::compare_(
const BasicFixedString& b) noexcept {
return detail::fixedstring::Cmp::LT ==
detail::fixedstring::compare_(
- a, 0u, folly::constexpr_strlen(a), b, 0u, b.size_);
+ a, 0u, folly::constexpr_strlen(a), b.data_, 0u, b.size_);
const Char* b) noexcept {
return detail::fixedstring::Cmp::LT ==
detail::fixedstring::compare_(
const Char* b) noexcept {
return detail::fixedstring::Cmp::LT ==
detail::fixedstring::compare_(
- a, 0u, a.size_, b, 0u, folly::constexpr_strlen(b));
+ a.data_, 0u, a.size_, b, 0u, folly::constexpr_strlen(b));
}
friend constexpr bool operator>(
}
friend constexpr bool operator>(
const BasicFixedString& b) noexcept {
return detail::fixedstring::Helper::concat_<Char>(
detail::fixedstring::checkNullTerminated(a),
const BasicFixedString& b) noexcept {
return detail::fixedstring::Helper::concat_<Char>(
detail::fixedstring::checkNullTerminated(a),
+ M - 1u,
+ b.data_,
+ b.size_,
std::make_index_sequence<N + M - 1u>{});
}
std::make_index_sequence<N + M - 1u>{});
}
const BasicFixedString& a,
const Char (&b)[M]) noexcept {
return detail::fixedstring::Helper::concat_<Char>(
const BasicFixedString& a,
const Char (&b)[M]) noexcept {
return detail::fixedstring::Helper::concat_<Char>(
detail::fixedstring::checkNullTerminated(b),
detail::fixedstring::checkNullTerminated(b),
std::make_index_sequence<N + M - 1u>{});
}
std::make_index_sequence<N + M - 1u>{});
}
const BasicFixedString& b) noexcept {
using A = const Char[2u];
return detail::fixedstring::Helper::concat_<Char>(
const BasicFixedString& b) noexcept {
using A = const Char[2u];
return detail::fixedstring::Helper::concat_<Char>(
- A{a, Char(0)}, b, std::make_index_sequence<N + 1u>{});
+ A{a, Char(0)},
+ 1u,
+ b.data_,
+ b.size_,
+ std::make_index_sequence<N + 1u>{});
Char b) noexcept {
using A = const Char[2u];
return detail::fixedstring::Helper::concat_<Char>(
Char b) noexcept {
using A = const Char[2u];
return detail::fixedstring::Helper::concat_<Char>(
- a, A{b, Char(0)}, std::make_index_sequence<N + 1u>{});
+ a.data_,
+ a.size_,
+ A{b, Char(0)},
+ 1u,
+ std::make_index_sequence<N + 1u>{});
constexpr bool operator==(
const BasicFixedString<Char, A>& a,
const BasicFixedString<Char, B>& b) noexcept {
constexpr bool operator==(
const BasicFixedString<Char, A>& a,
const BasicFixedString<Char, B>& b) noexcept {
- return detail::fixedstring::equal_(a, a.size(), b, b.size());
+ return detail::fixedstring::equal_(
+ detail::fixedstring::Helper::data_(a),
+ a.size(),
+ detail::fixedstring::Helper::data_(b),
+ b.size());
}
template <class Char, std::size_t A, std::size_t B>
}
template <class Char, std::size_t A, std::size_t B>
const BasicFixedString<Char, A>& a,
const BasicFixedString<Char, B>& b) noexcept {
return detail::fixedstring::Cmp::LT ==
const BasicFixedString<Char, A>& a,
const BasicFixedString<Char, B>& b) noexcept {
return detail::fixedstring::Cmp::LT ==
- detail::fixedstring::compare_(a, 0u, a.size(), b, 0u, b.size());
+ detail::fixedstring::compare_(
+ detail::fixedstring::Helper::data_(a),
+ 0u,
+ a.size(),
+ detail::fixedstring::Helper::data_(b),
+ 0u,
+ b.size());
}
template <class Char, std::size_t A, std::size_t B>
}
template <class Char, std::size_t A, std::size_t B>
const BasicFixedString<Char, N>& a,
const BasicFixedString<Char, M>& b) noexcept {
return detail::fixedstring::Helper::concat_<Char>(
const BasicFixedString<Char, N>& a,
const BasicFixedString<Char, M>& b) noexcept {
return detail::fixedstring::Helper::concat_<Char>(
- a, b, std::make_index_sequence<N + M>{});
+ detail::fixedstring::Helper::data_(a),
+ a.size(),
+ detail::fixedstring::Helper::data_(b),
+ b.size(),
+ std::make_index_sequence<N + M>{});
}
/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
}
/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
static_assert((alpha.rend() - 2) == (alpha.rbegin() + 24), "");
}
static_assert((alpha.rend() - 2) == (alpha.rbegin() + 24), "");
}
+namespace GCC61971 {
+ // FixedString runs afoul of GCC #61971 (spurious -Warray-bounds)
+ // in optimized builds. The following test case triggers it for gcc-4.x.
+ // Test that FixedString suppresses the warning correctly.
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61971
+ constexpr auto xyz = folly::makeFixedString("xyz");
+ constexpr auto dot = folly::makeFixedString(".");
+
+ template <typename T1>
+ constexpr auto concatStuff(const T1& component) noexcept {
+ return xyz + dot + component;
+ }
+ constexpr auto co = folly::makeFixedString("co");
+
+ struct S {
+ std::string s{concatStuff(co)};
+ };
+} // namespace GCC61971
+
+TEST(FixedStringGCC61971, GCC61971) {
+ GCC61971::S s;
+ (void)s;
+}
+
#include <folly/Range.h>
TEST(FixedStringConversionTest, ConversionToFollyRange) {
#include <folly/Range.h>
TEST(FixedStringConversionTest, ConversionToFollyRange) {