__addr_in_range is a non-constexpr function, so we can't call it during constant evaluation.
Details
- Reviewers
• Quuxplusone ldionne miscco var-const Mordante - Group Reviewers
Restricted Project - Commits
- rGaa8ebcad5dd5: [libc++] Remove recursion in basic_string::insert(const_iterator…
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
That was one of the things that pained me the most. We should really have something like __builtin_ranges_overlap without all the UB
I think this code looks correct enough, but it would be a lot less scary if you could just make __addr_in_range a non-constexpr function, instead of having it "lie" during constexpr evaluation and get us into infinite loops. E.g.:
if (__libcpp_is_constant_evaluated() || !__string_is_trivial_iterator<_ForwardIterator>::value || __addr_in_range(*__first)) { // Make a copy and then insert from the copy. const basic_string __temp(__first, __last, __alloc()); return __insert_from_safe_copy(__n, __ip, __temp.begin(), __temp.end()); } else { return __insert_from_safe_copy(__n, __ip, __first, __last); }
Note that __insert_from_safe_copy might be a better name than __insert_not_in_range, because being overlapping is just one of the many failure modes we need to guard against here.
Read (or re-read) https://quuxplusone.github.io/blog/2021/04/17/pathological-string-appends/ before deciding on this approach. "Burn the whole thing to the ground and rewrite it" might be a reasonable alternative, especially if the alternative is increasing the complexity of this already-complex code.
What would you like to see changed, other than the name? I don't really see a way to make this code simpler.
Yeah, simplifying might not be possible, and on closer inspection is at least not low-hanging fruit. Microsoft's insert is about as complicated these days: https://github.com/microsoft/STL/blob/8096a27/stl/inc/xstring#L3437-L3455
And __addr_in_range is already non-constexpr; let's keep it that way. My comment was based on your commit message, which said "__addr_in_range cannot be known during constant evaluation, so it has to always return true during constant evaluation" — that's incorrect. __addr_in_range is simply a non-constexpr function; it doesn't return anything during constant evaluation because it can't be called. (And this is as it should be.) Please update the commit message to say something like "__addr_in_range is a non-constexpr function, so we shouldn't call it during constant evaluation" or something like that.
Woops, I just saw this after I landed 5c53afe5aac0d295a9345cd439c6caf3ac5eb8ba. You'll want to rebase onto main.
LGTM; some remaining nits but they're all optional IIUC.
libcxx/include/string | ||
---|---|---|
1440 | Nit: I suggest following the guideline "Use the most aggressive constexpr possible for internal details," and I see no reason this couldn't be constexpr in C++14, right? | |
1466–1467 | Personally I wouldn't have touched these lines. But I don't really care. | |
2819 | Should you make my suggested change right now? Or are you planning to make it in whatever subsequent PR adds _LIBCPP_CONSTEXPR_AFTER_CXX17 to this insert method? |
Nit: I suggest following the guideline "Use the most aggressive constexpr possible for internal details," and I see no reason this couldn't be constexpr in C++14, right?