Add new test_descr_src_loc & and fix descr.h concat() src_loc bug discovered while working on the test.

This commit is contained in:
Ralf W. Grosse-Kunstleve 2022-07-11 16:27:38 -07:00
parent bd0dbd7cf5
commit 2a14ee6e48
3 changed files with 201 additions and 1 deletions

View File

@ -216,7 +216,8 @@ constexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) {
template <size_t N, typename... Ts, typename... Args>
constexpr auto concat(const descr<N, Ts...> &d, const Args &...args)
-> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {
return d + const_name(", ") + concat(args...);
// Ensure that src_loc of existing descr is used.
return d + const_name(", ", src_loc{nullptr, 0}) + concat(args...);
}
template <size_t N, typename... Ts>

View File

@ -0,0 +1,141 @@
// Copyright (c) 2022 The Pybind Development Team.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "pybind11_tests.h"
#if !defined(PYBIND11_CPP17)
// C++17 is required for the static constexpr inline definitions. Adapting
// this unit test to older compilers is more trouble than it is worth.
TEST_SUBMODULE(descr_src_loc, m) { m.attr("block_descr_offset") = py::none(); }
#else
namespace pybind11_tests {
namespace descr_src_loc {
using py::detail::const_name;
using py::detail::src_loc;
struct block_descr {
static constexpr unsigned offset = __LINE__;
static constexpr auto c0 = py::detail::descr<0>(src_loc::here());
static constexpr auto c1 = py::detail::descr<3>("Abc");
static constexpr auto c2 = py::detail::descr<1>(src_loc::here(), 'D');
static constexpr auto c3 = py::detail::descr<2>(src_loc::here(), 'E', 'f');
};
struct block_const_name {
static constexpr unsigned offset = __LINE__;
static constexpr auto c0 = const_name("G");
static constexpr auto c1 = const_name("Hi");
static constexpr auto c2 = const_name<0>();
static constexpr auto c3 = const_name<1>();
static constexpr auto c4 = const_name<23>();
static constexpr auto c5 = const_name<std::string>();
static constexpr auto c6 = const_name<true>("J", "K");
static constexpr auto c7 = const_name<false>("L", "M");
};
# ifdef PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY
struct block_underscore {
static constexpr unsigned offset = __LINE__;
// Using a macro to avoid copying the block_const_name code garbles the src_loc.line numbers.
static constexpr auto c0 = const_name("G");
static constexpr auto c1 = const_name("Hi");
static constexpr auto c2 = const_name<0>();
static constexpr auto c3 = const_name<1>();
static constexpr auto c4 = const_name<23>();
static constexpr auto c5 = const_name<std::string>();
static constexpr auto c6 = const_name<true>("J", "K");
static constexpr auto c7 = const_name<false>("L", "M");
};
# endif
struct block_plus {
static constexpr unsigned offset = __LINE__;
static constexpr auto c0 = const_name("N") + // critical line break
const_name("O");
static constexpr auto c1 = const_name("P", src_loc(nullptr, 0)) + // critical line break
const_name("Q");
};
struct block_concat {
static constexpr unsigned offset = __LINE__;
static constexpr auto c0 = py::detail::concat(const_name("R"));
static constexpr auto c1 = py::detail::concat(const_name("S"), // critical line break
const_name("T"));
static constexpr auto c2
= py::detail::concat(const_name("U", src_loc(nullptr, 0)), // critical line break
const_name("V"));
};
struct block_type_descr {
static constexpr unsigned offset = __LINE__;
static constexpr auto c0 = py::detail::type_descr(const_name("W"));
};
struct block_int_to_str {
static constexpr unsigned offset = __LINE__;
static constexpr auto c0 = py::detail::int_to_str<0>::digits;
static constexpr auto c1 = py::detail::int_to_str<4>::digits;
static constexpr auto c2 = py::detail::int_to_str<56>::digits;
};
} // namespace descr_src_loc
} // namespace pybind11_tests
TEST_SUBMODULE(descr_src_loc, m) {
using namespace pybind11_tests::descr_src_loc;
# define ATTR_OFFS(B) m.attr(# B "_offset") = B::offset;
# define ATTR_BLKC(B, C) \
m.attr(#B "_" #C) = py::make_tuple(B::C.text, B::C.sloc.file, B::C.sloc.line);
ATTR_OFFS(block_descr)
ATTR_BLKC(block_descr, c0)
ATTR_BLKC(block_descr, c1)
ATTR_BLKC(block_descr, c2)
ATTR_BLKC(block_descr, c3)
ATTR_OFFS(block_const_name)
ATTR_BLKC(block_const_name, c0)
ATTR_BLKC(block_const_name, c1)
ATTR_BLKC(block_const_name, c2)
ATTR_BLKC(block_const_name, c3)
ATTR_BLKC(block_const_name, c4)
ATTR_BLKC(block_const_name, c5)
ATTR_BLKC(block_const_name, c6)
ATTR_BLKC(block_const_name, c7)
ATTR_OFFS(block_underscore)
ATTR_BLKC(block_underscore, c0)
ATTR_BLKC(block_underscore, c1)
ATTR_BLKC(block_underscore, c2)
ATTR_BLKC(block_underscore, c3)
ATTR_BLKC(block_underscore, c4)
ATTR_BLKC(block_underscore, c5)
ATTR_BLKC(block_underscore, c6)
ATTR_BLKC(block_underscore, c7)
ATTR_OFFS(block_plus)
ATTR_BLKC(block_plus, c0)
ATTR_BLKC(block_plus, c1)
ATTR_OFFS(block_concat)
ATTR_BLKC(block_concat, c0)
ATTR_BLKC(block_concat, c1)
ATTR_BLKC(block_concat, c2)
ATTR_OFFS(block_type_descr)
ATTR_BLKC(block_type_descr, c0)
ATTR_OFFS(block_int_to_str)
ATTR_BLKC(block_int_to_str, c0)
ATTR_BLKC(block_int_to_str, c1)
ATTR_BLKC(block_int_to_str, c2)
}
#endif // PYBIND11_CPP17

View File

@ -0,0 +1,58 @@
import pytest
from pybind11_tests import descr_src_loc as m
if m.block_descr_offset is None:
block_parametrize = (("all_blocks", None),)
else:
block_parametrize = (
("block_descr", (("", 1), ("Abc", 2), ("D", 3), ("Ef", 4))),
(
"block_const_name",
(
("G", 1),
("Hi", 2),
("0", 0),
("1", 0),
("23", 0),
("%", 6),
("J", 7),
("M", 8),
),
),
(
"block_underscore",
(
("G", 2),
("Hi", 3),
("0", 0),
("1", 0),
("23", 0),
("%", 7),
("J", 8),
("M", 9),
),
),
("block_plus", (("NO", 1), ("PQ", 4))),
("block_concat", (("R", 1), ("S, T", 2), ("U, V", 6))),
("block_type_descr", (("{W}", 1),)),
("block_int_to_str", (("", 0), ("4", 0), ("56", 0))),
)
@pytest.mark.skipif(
m.block_descr_offset is None, reason="C++17 is required for this unit test."
)
@pytest.mark.parametrize("block_name, expected_text_line", block_parametrize)
def test_block(block_name, expected_text_line):
offset = getattr(m, f"{block_name}_offset")
for ix, (expected_text, expected_line) in enumerate(expected_text_line):
text, file, line = getattr(m, f"{block_name}_c{ix}")
assert text == expected_text
if expected_line:
assert file is not None, expected_text_line
assert file.endswith("test_descr_src_loc.cpp")
assert line == offset + expected_line
else:
assert file is None
assert line == 0