diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -256,7 +256,7 @@ "`3807 `__","The feature test macro for ``ranges::find_last`` should be renamed","February 2023","","","|ranges|" "`3811 `__","``views::as_const`` on ``ref_view`` should return ``ref_view``","February 2023","","","|ranges|" "`3820 `__","``cartesian_product_view::iterator::prev`` is not quite right","February 2023","","","|ranges|" -"`3825 `__","Missing compile-time argument ``id`` check in ``basic_format_parse_context::next_arg_id``","February 2023","","","|format|" +"`3825 `__","Missing compile-time argument ``id`` check in ``basic_format_parse_context::next_arg_id``","February 2023","|Complete|","17.0","|format|" "`3204 `__","``sub_match::swap`` only swaps the base class","February 2023","|Complete|","17.0","" "`3733 `__","``ranges::to`` misuses ``cpp17-input-iterator``","February 2023","","","|ranges|" "`3742 `__","``deque::prepend_range`` needs to permute","February 2023","","","|ranges|" diff --git a/libcxx/include/__format/format_parse_context.h b/libcxx/include/__format/format_parse_context.h --- a/libcxx/include/__format/format_parse_context.h +++ b/libcxx/include/__format/format_parse_context.h @@ -59,6 +59,18 @@ if (__indexing_ == __unknown) __indexing_ = __automatic; + + // Throws an exception to make the expression a non core constant + // expression as required by: + // [format.parse.ctx]/8 + // Remarks: Let cur-arg-id be the value of next_arg_id_ prior to this + // call. Call expressions where cur-arg-id >= num_args_ is true are not + // core constant expressions (7.7 [expr.const]). + // Note: the Throws clause [format.parse.ctx]/9 doesn't specify the + // behavior when id >= num_args_. + if (is_constant_evaluated() && __next_arg_id_ >= __num_args_) + std::__throw_format_error("Argument index outside the valid range"); + return __next_arg_id_++; } _LIBCPP_HIDE_FROM_ABI constexpr void check_arg_id(size_t __id) { diff --git a/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/next_arg_id.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/next_arg_id.pass.cpp --- a/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/next_arg_id.pass.cpp +++ b/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/next_arg_id.pass.cpp @@ -25,7 +25,7 @@ #include "test_macros.h" constexpr bool test() { - std::format_parse_context context(""); + std::format_parse_context context("", 10); for (size_t i = 0; i < 10; ++i) assert(i == context.next_arg_id()); diff --git a/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/next_arg_id.verify.cpp b/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/next_arg_id.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.parse.ctx/next_arg_id.verify.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// 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++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-format + +// constexpr size_t next_arg_id() + +#include + +#include "test_macros.h" + +constexpr bool test() { + // [format.parse.ctx]/8 + // Let cur-arg-id be the value of next_arg_id_ prior to this call. Call + // expressions where cur-arg-id >= num_args_ is true are not core constant + // expressions (7.7 [expr.const]). + std::format_parse_context context("", 0); + context.next_arg_id(); + + return true; +} + +int main(int, char**) { + // expected-error-re@+1 {{{{(static_assert|static assertion)}} expression is not an integral constant expression}} + static_assert(test()); + + return 0; +}