miniscript: make operator_mst consteval

It seems modern compilers don't realize that all invocations of operator""_mst
can be evaluated at compile time, despite the constexpr keyword.

Since C++20, we can force them to evaluate at compile time, turning all the
miniscript type constants into actual compile-time constants.

It appears that MSVC does not support consteval operator"" when used inside
a ternary operator (??). For the few places where this happens, define a
constant outside the operator call.
This commit is contained in:
Pieter Wuille 2023-10-16 10:17:12 -04:00
parent 40bc501bf4
commit 190fa2a95b
2 changed files with 15 additions and 12 deletions

View File

@ -231,7 +231,8 @@ Type ComputeType(Fragment fragment, Type x, Type y, Type z, const std::vector<Ty
Type acc_tl = "k"_mst;
for (size_t i = 0; i < sub_types.size(); ++i) {
Type t = sub_types[i];
if (!(t << (i ? "Wdu"_mst : "Bdu"_mst))) return ""_mst; // Require Bdu, Wdu, Wdu, ...
static constexpr auto WDU{"Wdu"_mst}, BDU{"Bdu"_mst};
if (!(t << (i ? WDU : BDU))) return ""_mst; // Require Bdu, Wdu, Wdu, ...
if (!(t << "e"_mst)) all_e = false;
if (!(t << "m"_mst)) all_m = false;
if (t << "s"_mst) num_s += 1;

View File

@ -123,12 +123,12 @@ class Type {
//! Internal bitmap of properties (see ""_mst operator for details).
uint32_t m_flags;
//! Internal constructor used by the ""_mst operator.
explicit constexpr Type(uint32_t flags) : m_flags(flags) {}
//! Internal constructor.
explicit constexpr Type(uint32_t flags) noexcept : m_flags(flags) {}
public:
//! The only way to publicly construct a Type is using this literal operator.
friend constexpr Type operator"" _mst(const char* c, size_t l);
//! Construction function used by the ""_mst operator.
static consteval Type Make(uint32_t flags) noexcept { return Type(flags); }
//! Compute the type with the union of properties.
constexpr Type operator|(Type x) const { return Type(m_flags | x.m_flags); }
@ -150,11 +150,11 @@ public:
};
//! Literal operator to construct Type objects.
inline constexpr Type operator"" _mst(const char* c, size_t l) {
Type typ{0};
inline consteval Type operator"" _mst(const char* c, size_t l) {
Type typ{Type::Make(0)};
for (const char *p = c; p < c + l; p++) {
typ = typ | Type(
typ = typ | Type::Make(
*p == 'B' ? 1 << 0 : // Base type
*p == 'V' ? 1 << 1 : // Verify type
*p == 'K' ? 1 << 2 : // Key type
@ -548,7 +548,8 @@ private:
for (const auto& sub : subs) {
subsize += sub->ScriptSize();
}
Type sub0type = subs.size() > 0 ? subs[0]->GetType() : ""_mst;
static constexpr auto NONE_MST{""_mst};
Type sub0type = subs.size() > 0 ? subs[0]->GetType() : NONE_MST;
return internal::ComputeScriptLen(fragment, sub0type, subsize, k, subs.size(), keys.size(), m_script_ctx);
}
@ -712,9 +713,10 @@ private:
for (const auto& sub : subs) sub_types.push_back(sub->GetType());
}
// All other nodes than THRESH can be computed just from the types of the 0-3 subexpressions.
Type x = subs.size() > 0 ? subs[0]->GetType() : ""_mst;
Type y = subs.size() > 1 ? subs[1]->GetType() : ""_mst;
Type z = subs.size() > 2 ? subs[2]->GetType() : ""_mst;
static constexpr auto NONE_MST{""_mst};
Type x = subs.size() > 0 ? subs[0]->GetType() : NONE_MST;
Type y = subs.size() > 1 ? subs[1]->GetType() : NONE_MST;
Type z = subs.size() > 2 ? subs[2]->GetType() : NONE_MST;
return SanitizeType(ComputeType(fragment, x, y, z, sub_types, k, data.size(), subs.size(), keys.size(), m_script_ctx));
}