mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-23 03:03:57 +08:00
Make union_ptr_t's constructor statically type safe
Ensure it cannot be constructed from the wrong node type.
This commit is contained in:
parent
8d37be2916
commit
a8eb2a6813
43
src/ast.h
43
src/ast.h
|
@ -103,6 +103,19 @@ const wchar_t *ast_type_to_string(type_t type);
|
|||
* };
|
||||
*/
|
||||
|
||||
namespace template_goo {
|
||||
/// \return true if type Type is in the Candidates list.
|
||||
template <typename Type>
|
||||
constexpr bool type_in_list() {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Type, typename Candidate, typename... Rest>
|
||||
constexpr bool type_in_list() {
|
||||
return std::is_same<Type, Candidate>::value || type_in_list<Type, Rest...>();
|
||||
}
|
||||
} // namespace template_goo
|
||||
|
||||
// A union pointer field is a pointer to one of a fixed set of node types.
|
||||
// It is never null after construction.
|
||||
template <typename... Nodes>
|
||||
|
@ -127,9 +140,8 @@ struct union_ptr_t {
|
|||
|
||||
template <typename Node>
|
||||
/* implicit */ union_ptr_t(std::unique_ptr<Node> n) : contents(std::move(n)) {
|
||||
// TODO: this could be made statically type safe.
|
||||
assert(contents != nullptr && allows_node(*contents) &&
|
||||
"union_ptr constructed from invalid node type");
|
||||
static_assert(template_goo::type_in_list<Node, Nodes...>(),
|
||||
"Cannot construct from this node type");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -153,7 +165,7 @@ struct optional_t {
|
|||
bool has_value() const { return contents != nullptr; }
|
||||
};
|
||||
|
||||
namespace horrible_template_goop {
|
||||
namespace template_goo {
|
||||
|
||||
// void if B is true, SFINAE'd away otherwise.
|
||||
template <bool B>
|
||||
|
@ -198,14 +210,14 @@ void accept_field_visitor(FieldVisitor &v, bool reverse, Field &field, Rest &...
|
|||
if (reverse) visit_1_field(v, field);
|
||||
}
|
||||
|
||||
} // namespace horrible_template_goop
|
||||
} // namespace template_goo
|
||||
|
||||
#define FIELDS(...) \
|
||||
template <typename FieldVisitor> \
|
||||
void accept(FieldVisitor &visitor, bool reversed = false) { \
|
||||
visitor.will_visit_fields_of(*this); \
|
||||
horrible_template_goop::accept_field_visitor(visitor, reversed, __VA_ARGS__); \
|
||||
visitor.did_visit_fields_of(*this); \
|
||||
#define FIELDS(...) \
|
||||
template <typename FieldVisitor> \
|
||||
void accept(FieldVisitor &visitor, bool reversed = false) { \
|
||||
visitor.will_visit_fields_of(*this); \
|
||||
template_goo::accept_field_visitor(visitor, reversed, __VA_ARGS__); \
|
||||
visitor.did_visit_fields_of(*this); \
|
||||
}
|
||||
|
||||
/// node_t is the base node of all AST nodes.
|
||||
|
@ -778,15 +790,6 @@ bool keyword_t<KWs...>::allows_keyword(parse_keyword_t kw) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
template <typename... Nodes>
|
||||
bool union_ptr_t<Nodes...>::allows_node(const node_t &node) {
|
||||
for (type_t t : {Nodes::AstType...}) {
|
||||
if (t == node.type) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A node visitor is like a field visitor, but adapted to only visit actual nodes, as const
|
||||
* references. It calls the visit() function of its visitor with a const reference to each node
|
||||
|
|
Loading…
Reference in New Issue
Block a user