Skip to content

Conversation

@vinay-deshmukh
Copy link
Contributor

@vinay-deshmukh vinay-deshmukh commented Apr 4, 2025

Fixes #128660

Depends on:

  1. [NFC][libc++] Fix typo in libcxx/include/__memory/pointer_traits.h #157304
  2. [libc++] Remove UB from std::__tree_node construction #153908

Summary:

  1. Apply _LIBCPP_CONSTEXPR_SINCE_CXX26 to map, __tree, node-handle, __libcpp_erase_if, __lazy_synth_three_way_comparator, __lazy_compare_result, libcxx/include/__utility/try_key_extraction.h

  2. Skip test erase_if.pass.cpp for GCC during constant evaluation. AFAICT this appears to be a g++ bug, as the test passes with clang

  3. Disable test for node-handle::key() during constant evaluation (CWG2514). It is annotated with a // FIXME

  4. map.modifiers/try.emplace.pass.cpp : Start using the previously unused mv3. (Should this be a separate patch?)

  5. Has a TODO for multimap and ohters
    a. libcxx/test/std/containers/associative/map/map.ops/contains.pass.cpp
    b. libcxx/test/std/containers/associative/map/map.ops/contains_transparent.pass.cpp
    a. libcxx/test/std/containers/container.node/node_handle.pass.cpp

  6. Fix typo in libcxx/include/__memory/pointer_traits.h -> [NFC][libc++] Fix typo in libcxx/include/__memory/pointer_traits.h #157304

  7. pair<const MoveOnly, ...>
    a. move_assign.pass.cpp
    b. move_alloc.pass.cpp
    c. Fails to compile if static_assert(test()); is called in the test file
    d. Has a // FIXME with commented code

  8. Change __tree_node to construct it's __node_value_type during construction to avoid the: note: member call on object outside its lifetime is not allowed in a constant expression issue. This became -> [libc++] Remove UB from std::__tree_node construction #153908

@github-actions
Copy link

github-actions bot commented Apr 4, 2025

⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo.
Please turn off Keep my email addresses private setting in your account.
See LLVM Discourse for more information.

@github-actions
Copy link

github-actions bot commented Apr 4, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@vinay-deshmukh vinay-deshmukh force-pushed the vinay-issue-128660-P3372-constexpr-map branch 2 times, most recently from 46d0bb9 to 9ea718f Compare April 7, 2025 22:25
@vinay-deshmukh
Copy link
Contributor Author

At this point, I have fixed all the trivially fixable issues as far as I can tell, but naturally trying to fix the lifetime issue I saw when trying to fix it in:

cec33fb

(need explicit constructors for std::__value_type and __tree_node_base to start the lifetime of a node at

https://github.com/llvm/llvm-project/blame/900d44976c89477607946fad4493e4b9ac09346f/libcxx/include/__tree#L1956)

And that has resulted in a im-perfect forwarding (I think)

I did find this commit that mentions that the code is UB (slightly less than previously), so maybe constexpr flagging that is expected

f52318b | https://reviews.llvm.org/D47607

@frederick-vs-ja

@frederick-vs-ja
Copy link
Contributor

I did find this commit that mentions that the code is UB (slightly less than previously), so maybe constexpr flagging that is expected

f52318b | https://reviews.llvm.org/D47607

This is clearly UB in the core language. Per current rules we can't assign the first data member of a pair<const int, int>, even when the complete object is non-const.

IIUC we need to perform different operations (e.g. reconstructing the node) in constant evaluation.

@vinay-deshmukh
Copy link
Contributor Author

Update:

Need to wait for #134819 to be merged before this PR can proceed.

That PR should get rid of some more UB, and later I should be able to:

There's still some UB left, but that' only in the __assign_value and __insert_from_orphaned_node functions, where you should be able to just destroy/construct instead of assigning to remove any UB during constant evaluation.

From Discord by philnik777

@vinay-deshmukh vinay-deshmukh force-pushed the vinay-issue-128660-P3372-constexpr-map branch from 7906780 to 0cce96e Compare June 9, 2025 01:07
@vinay-deshmukh vinay-deshmukh requested a review from Zingam October 18, 2025 19:24
- P3060R3: Add ``std::views::indices(n)`` (`Github <https://llvm.org/PR148175>`__)
- P2835R7: Expose ``std::atomic_ref``'s object address (`Github <https://llvm.org/PR118377>`__)
- P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
- P3372R3: ``constexpr map`` (`Github <https://llvm.org/PR134330>`__) (The paper is partially implemented. ``constexpr map`` is implemented in this release)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to add this release note for a partially implemented paper. You can update the status page though.

Copy link
Contributor Author

@vinay-deshmukh vinay-deshmukh Oct 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking at this PR for a reference:
https://github.com/llvm/llvm-project/pull/137453/files

So Cxx2cPapers.csv already has an entry for it:

"`P3372R3 <https://wg21.link/P3372R3>`__","constexpr containers and adaptors","2025-02 (Hagenberg)","|In Progress|","","`#127876 <https://github.com/llvm/llvm-project/issues/127876>`__",""

and I originally added it here using this as a reference:

- P3372R3: ``constexpr`` containers and adaptors (`Github <https://github.com/llvm/llvm-project/issues/127876>`__) (``forward_list``, ``list``, ``priority_queue``, ``flat_map``, and ``flat_set`` are implemented)

So perhaps should I just remove this line for this review?

removed in 483a33b

// within __insert_unique_from_orphaned_node, the code will fail to compile where the value is not
// copy_constructible for runtime execution as well; unless we use `if constexpr`. Given the copy-constructible
// code path will be a performance regression, we want to restrict it to only execute during constant evaluation
//, we need to delay the template instantiation
Copy link
Contributor

@H-G-Hristov H-G-Hristov Oct 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
//, we need to delay the template instantiation
//, we need to delay the template instantiation.

Nit. Please do this everywhere too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a few . and capitalized first letters of sentences. Rewrote some parts.

69bb9d3

let me know if this is better!

Comment on lines 1450 to 1465
// we use copy, and not "move" as the constraint
// because we can NOT move from `const key_type`, which is how `value_type` is defined
// atleast for map
// typedef pair<const key_type, mapped_type> value_type;
// so we must copy it

// const_cast is not allowed at constexpr time.
// we get around this by deleting __lhs and creating a new node in-place
// to avoid const_cast __lhs.first

// We create a sfinae wrapper method here, because if the body of the true_type overload for
// __assign_value__sfinae() gets template instantiated within __assign_value, the code will fail to compile where
// the value is not copy_constructible for runtime execution as well; unless we use `if constexpr`. Given the
// copy-constructible code path will be a performance regression, we want to restrict it to only execute during
// constant evaluation
//, we need to delay the template instantiation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit formatted oddly, could you please update it and add punctuation, e.g (not complete).

Suggested change
// we use copy, and not "move" as the constraint
// because we can NOT move from `const key_type`, which is how `value_type` is defined
// atleast for map
// typedef pair<const key_type, mapped_type> value_type;
// so we must copy it
// const_cast is not allowed at constexpr time.
// we get around this by deleting __lhs and creating a new node in-place
// to avoid const_cast __lhs.first
// We create a sfinae wrapper method here, because if the body of the true_type overload for
// __assign_value__sfinae() gets template instantiated within __assign_value, the code will fail to compile where
// the value is not copy_constructible for runtime execution as well; unless we use `if constexpr`. Given the
// copy-constructible code path will be a performance regression, we want to restrict it to only execute during
// constant evaluation
//, we need to delay the template instantiation
// We use copy, and not "move" as the constraint because we can NOT move from `const key_type`, which is how `value_type` is defined
// atleast for map
// typedef pair<const key_type, mapped_type> value_type;
// so we must copy it
// const_cast is not allowed at constexpr time.
// we get around this by deleting __lhs and creating a new node in-place
// to avoid const_cast __lhs.first
// We create a sfinae wrapper method here, because if the body of the true_type overload for
// __assign_value__sfinae() gets template instantiated within __assign_value, the code will fail to compile where
// the value is not copy_constructible for runtime execution as well; unless we use `if constexpr`. Given the
// copy-constructible code path will be a performance regression, we want to restrict it to only execute during
// constant evaluation, we need to delay the template instantiation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a few . and capitalized first letters of sentences. Rewrote some parts.

69bb9d3

let me know if this is better!

Comment on lines 139 to 142
constexpr iterator emplace_hint(const_iterator position, Args&&... args); // constexpr since C++26
constexpr pair<iterator, bool> insert(const value_type& v); // constexpr since C++26
constexpr pair<iterator, bool> insert( value_type&& v); // C++17, constexpr
since C++26
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
constexpr iterator emplace_hint(const_iterator position, Args&&... args); // constexpr since C++26
constexpr pair<iterator, bool> insert(const value_type& v); // constexpr since C++26
constexpr pair<iterator, bool> insert( value_type&& v); // C++17, constexpr
since C++26
constexpr iterator emplace_hint(const_iterator position, Args&&... args); // constexpr since C++26
constexpr pair<iterator, bool> insert(const value_type& v); // constexpr since C++26
constexpr pair<iterator, bool> insert( value_type&& v); // C++17, constexpr since C++26

Can you align these comments a bit?

Copy link
Contributor Author

@vinay-deshmukh vinay-deshmukh Oct 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in
66b4d6f

Aligned it to each "stanza" / section, let me know if this looks good

@vinay-deshmukh vinay-deshmukh force-pushed the vinay-issue-128660-P3372-constexpr-map branch from 8658eee to 66b4d6f Compare October 19, 2025 10:27
@vinay-deshmukh
Copy link
Contributor Author

The latest failure:

  diff -u /home/gha/actions-runner/_work/llvm-project/llvm-project/build/generic-cxx26/libcxx/test/libcxx/module_std_compat.gen.py/Output/module_std_compat.sh.cpp.dir/t.tmp.cuchar.module /home/gha/actions-runner/_work/llvm-project/llvm-project/build/generic-cxx26/libcxx/test/libcxx/module_std_compat.gen.py/Output/module_std_compat.sh.cpp.dir/t.tmp.cuchar.include
  # executed command: diff -u /home/gha/actions-runner/_work/llvm-project/llvm-project/build/generic-cxx26/libcxx/test/libcxx/module_std_compat.gen.py/Output/module_std_compat.sh.cpp.dir/t.tmp.cuchar.module /home/gha/actions-runner/_work/llvm-project/llvm-project/build/generic-cxx26/libcxx/test/libcxx/module_std_compat.gen.py/Output/module_std_compat.sh.cpp.dir/t.tmp.cuchar.include
  # .---command stdout------------
  # | --- /home/gha/actions-runner/_work/llvm-project/llvm-project/build/generic-cxx26/libcxx/test/libcxx/module_std_compat.gen.py/Output/module_std_compat.sh.cpp.dir/t.tmp.cuchar.module
  # | +++ /home/gha/actions-runner/_work/llvm-project/llvm-project/build/generic-cxx26/libcxx/test/libcxx/module_std_compat.gen.py/Output/module_std_compat.sh.cpp.dir/t.tmp.cuchar.include
  # | @@ -1,9 +1,7 @@
  # |  using ::c16rtomb;
  # |  using ::c32rtomb;
  # | -using ::c8rtomb;
  # |  using ::mbrtoc16;
  # |  using ::mbrtoc32;
  # | -using ::mbrtoc8;
  # |  using ::std::c16rtomb;
  # |  using ::std::c32rtomb;
  # |  using ::std::c8rtomb;
  # `-----------------------------
  # error: command failed with exit status: 1

seems to be related to this: #152724

not sure why that is failing however

@vinay-deshmukh
Copy link
Contributor Author

@frederick-vs-ja @philnik777 @H-G-Hristov @Zingam

Can you take a look at this pull request when you have a chance? Thank you!

@vinay-deshmukh
Copy link
Contributor Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++26 libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[libc++] P3372R3: constexpr map

7 participants