fixed inline tables being mutable through table headers (closes #131)

This commit is contained in:
Mark Gillard 2022-01-05 16:47:00 +02:00
parent de2413e0ef
commit 7d3770df92
9 changed files with 134 additions and 74 deletions

View File

@ -36,7 +36,7 @@ code changes at callsites or in build systems are indicated with ⚠️.
- fixed parser not correctly round-tripping the format of binary and octal integers in some cases
- fixed strong exception guarantee edge-cases in `toml::table` and `toml::array`
- fixed some incorrect unicode scalar sequence transformations (#125)
- fixed a number of spec conformance issues (#127, #128, #129) (@moorereason)
- fixed a number of spec conformance issues (#127, #128, #129, #130, #131) (@moorereason)
#### Additions:
- added `operator->` to `toml::value` for class types

View File

@ -30,6 +30,7 @@ namespace
"val = {a='b',"sv,
"val = {a='b',\n c='d'}"sv, // allowed when TOML_ENABLE_UNRELEASED_FEATURES == 1
"val = {?='b'}"sv,
"foo = {} \n [foo.bar]"sv,
"########## tables"sv,
"[]"sv,

View File

@ -783,10 +783,7 @@ TOML_ANON_NAMESPACE_START
#endif
}
error_builder(const error_builder&) = delete;
error_builder(error_builder&&) = delete;
error_builder& operator=(const error_builder&) = delete;
error_builder& operator=(error_builder&&) = delete;
TOML_DELETE_DEFAULTS(error_builder);
};
struct parse_scope
@ -807,16 +804,13 @@ TOML_ANON_NAMESPACE_START
storage_ = parent_;
}
parse_scope(const parse_scope&) = delete;
parse_scope(parse_scope&&) = delete;
parse_scope& operator=(const parse_scope&) = delete;
parse_scope& operator=(parse_scope&&) = delete;
TOML_DELETE_DEFAULTS(parse_scope);
};
#define push_parse_scope_2(scope, line) parse_scope ps_##line(current_scope, scope)
#define push_parse_scope_1(scope, line) push_parse_scope_2(scope, line)
#define push_parse_scope(scope) push_parse_scope_1(scope, __LINE__)
struct parsed_key_buffer
struct parse_key_buffer
{
std::string buffer;
std::vector<std::pair<size_t, size_t>> segments;
@ -864,25 +858,23 @@ TOML_ANON_NAMESPACE_START
}
};
struct parse_depth_counter
struct depth_counter_scope
{
size_t& depth_;
TOML_NODISCARD_CTOR
explicit parse_depth_counter(size_t& depth) noexcept : depth_{ depth }
explicit depth_counter_scope(size_t& depth) noexcept //
: depth_{ depth }
{
depth_++;
}
~parse_depth_counter() noexcept
~depth_counter_scope() noexcept
{
depth_--;
}
parse_depth_counter(const parse_depth_counter&) = delete;
parse_depth_counter(parse_depth_counter&&) = delete;
parse_depth_counter& operator=(const parse_depth_counter&) = delete;
parse_depth_counter& operator=(parse_depth_counter&&) = delete;
TOML_DELETE_DEFAULTS(depth_counter_scope);
};
struct parsed_string
@ -890,6 +882,25 @@ TOML_ANON_NAMESPACE_START
std::string_view value;
bool was_multi_line;
};
struct table_vector_scope
{
std::vector<table*>& tables;
TOML_NODISCARD_CTOR
explicit table_vector_scope(std::vector<table*>& tables_, table& tbl) //
: tables{ tables_ }
{
tables.push_back(&tbl);
}
~table_vector_scope() noexcept
{
tables.pop_back();
}
TOML_DELETE_DEFAULTS(table_vector_scope);
};
}
TOML_ANON_NAMESPACE_END;
@ -1013,8 +1024,9 @@ TOML_IMPL_NAMESPACE_START
const utf8_codepoint* cp = {};
std::vector<table*> implicit_tables;
std::vector<table*> dotted_key_tables;
std::vector<table*> open_inline_tables;
std::vector<array*> table_arrays;
parsed_key_buffer key_buffer;
parse_key_buffer key_buffer;
std::string string_buffer;
std::string recording_buffer; // for diagnostics
bool recording = false, recording_whitespace = true;
@ -1038,10 +1050,7 @@ TOML_IMPL_NAMESPACE_START
void set_error_at(source_position pos, const T&... reason) const
{
static_assert(sizeof...(T) > 0);
#if !TOML_EXCEPTIONS
if (err)
return;
#endif
return_if_error();
error_builder builder{ current_scope };
(builder.append(reason), ...);
@ -2452,8 +2461,8 @@ TOML_IMPL_NAMESPACE_START
TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
push_parse_scope("value"sv);
const parse_depth_counter depth_counter{ nested_values };
if (nested_values > max_nested_values)
const depth_counter_scope depth_counter{ nested_values };
if TOML_UNLIKELY(nested_values > max_nested_values)
set_error_and_return_default("exceeded maximum nested value depth of "sv,
static_cast<uint64_t>(max_nested_values),
" (TOML_MAX_NESTED_VALUES)"sv);
@ -3099,7 +3108,15 @@ TOML_IMPL_NAMESPACE_START
node& p = pit->second;
if (auto tbl = p.as_table())
{
// adding to closed inline tables is illegal
if (tbl->is_inline() && !impl::find(open_inline_tables.begin(), open_inline_tables.end(), tbl))
set_error_and_return_default("cannot insert '"sv,
to_sv(recording_buffer),
"' into existing inline table"sv);
parent = tbl;
}
else if (auto arr = p.as_array(); arr && impl::find(table_arrays.begin(), table_arrays.end(), arr))
{
// table arrays are a special case;
@ -3264,7 +3281,9 @@ TOML_IMPL_NAMESPACE_START
if (pit != tbl->end() && pit->first == segment)
{
table* p = pit->second.as_table();
if (!p
// redefinition
if TOML_UNLIKELY(!p
|| !(impl::find(dotted_key_tables.begin(), dotted_key_tables.end(), p)
|| impl::find(implicit_tables.begin(), implicit_tables.end(), p)))
{
@ -3523,6 +3542,8 @@ TOML_IMPL_NAMESPACE_START
node_ptr tbl_ptr{ new table{} };
table& tbl = tbl_ptr->ref_cast<table>();
tbl.is_inline(true);
table_vector_scope table_scope{ open_inline_tables, tbl };
enum TOML_CLOSED_ENUM parse_elem : int
{
none,
@ -3530,7 +3551,6 @@ TOML_IMPL_NAMESPACE_START
kvp
};
parse_elem prev = none;
while (!is_error())
{
if constexpr (TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)

View File

@ -517,9 +517,6 @@
//# ATTRIBUTES, UTILITY MACROS ETC
//#====================================================================================================================
#if TOML_GCC || TOML_CLANG || (TOML_ICC && !TOML_ICC_CL)
// not supported by any version of GCC or Clang as of 26/11/2020
// not supported by any version of ICC on Linux as of 11/01/2021
@ -748,6 +745,12 @@
#define TOML_UNUSED(...) static_cast<void>(__VA_ARGS__)
#define TOML_DELETE_DEFAULTS(T) \
T(const T&) = delete; \
T(T&&) = delete; \
T& operator=(const T&) = delete; \
T& operator=(T&&) = delete
//======================================================================================================================
// SFINAE
//======================================================================================================================

View File

@ -92,6 +92,7 @@ TOML_POP_WARNINGS;
#undef TOML_CONST_GETTER
#undef TOML_CONST_INLINE_GETTER
#undef TOML_CONSTRAINED_TEMPLATE
#undef TOML_DELETE_DEFAULTS
#undef TOML_DISABLE_ARITHMETIC_WARNINGS
#undef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
#undef TOML_DISABLE_SPAM_WARNINGS

View File

@ -247,4 +247,12 @@ b = []
parse_expected_value(FILE_LINE_ARGS, "0400-01-01T00:00:00"sv, toml::date_time{ { 400, 1, 1 }, { 0, 0, 0 } });
parse_expected_value(FILE_LINE_ARGS, "1000-01-01 00:00:00"sv, toml::date_time{ { 1000, 1, 1 }, { 0, 0, 0 } });
}
SECTION("github/issues/131") // https://github.com/marzer/tomlplusplus/issues/131
{
parsing_should_fail(FILE_LINE_ARGS, R"(
a={}
[a.b]
)"sv);
}
}

View File

@ -10,7 +10,7 @@ using namespace std::string_view_literals;
TOML_NAMESPACE_START
{
void to_json(json & j, const value<std::string>& val)
static void to_json(json & j, const value<std::string>& val)
{
j["type"] = "string";
j["value"] = *val;
@ -29,52 +29,52 @@ TOML_NAMESPACE_START
j["value"] = ss.str();
}
void to_json(json & j, const value<int64_t>& val)
static void to_json(json & j, const value<int64_t>& val)
{
j["type"] = "integer";
to_json_via_stream(j, val);
}
void to_json(json & j, const value<double>& val)
static void to_json(json & j, const value<double>& val)
{
j["type"] = "float";
to_json_via_stream(j, val);
}
void to_json(json & j, const value<bool>& val)
static void to_json(json & j, const value<bool>& val)
{
j["type"] = "bool";
to_json_via_stream(j, val);
}
void to_json(json & j, const value<date>& val)
static void to_json(json & j, const value<date>& val)
{
j["type"] = "date-local";
to_json_via_stream(j, val);
}
void to_json(json & j, const value<time>& val)
static void to_json(json & j, const value<time>& val)
{
j["type"] = "time-local";
to_json_via_stream(j, val);
}
void to_json(json & j, const value<date_time>& val)
static void to_json(json & j, const value<date_time>& val)
{
j["type"] = val->is_local() ? "datetime-local" : "datetime";
to_json_via_stream(j, val);
}
void to_json(json&, const array&);
static void to_json(json&, const array&);
void to_json(json & j, const table& tbl)
static void to_json(json & j, const table& tbl)
{
j = json::object();
for (auto& [k_, v_] : tbl)
v_.visit([&, k = &k_](auto& v) { j[std::string{ k->str() }] = v; });
}
void to_json(json & j, const array& arr)
static void to_json(json & j, const array& arr)
{
j = json::array();
for (auto& v_ : arr)

View File

@ -20,7 +20,7 @@ using namespace std::string_view_literals;
TOML_NAMESPACE_START
{
void from_json(const json& j, value<std::string>& val)
static void from_json(const json& j, value<std::string>& val)
{
assert(is_tt_value(j));
assert(j["type"] == "string");
@ -54,7 +54,7 @@ TOML_NAMESPACE_START
});
}
void from_json(const json& j, value<int64_t>& val)
static void from_json(const json& j, value<int64_t>& val)
{
assert(is_tt_value(j));
assert(j["type"] == "integer");
@ -62,7 +62,7 @@ TOML_NAMESPACE_START
from_json_via_parse(j, val);
}
void from_json(const json& j, value<double>& val)
static void from_json(const json& j, value<double>& val)
{
assert(is_tt_value(j));
assert(j["type"] == "float");
@ -70,7 +70,7 @@ TOML_NAMESPACE_START
from_json_via_parse(j, val);
}
void from_json(const json& j, value<bool>& val)
static void from_json(const json& j, value<bool>& val)
{
assert(is_tt_value(j));
assert(j["type"] == "bool");
@ -78,7 +78,7 @@ TOML_NAMESPACE_START
from_json_via_parse(j, val);
}
void from_json(const json& j, value<date>& val)
static void from_json(const json& j, value<date>& val)
{
assert(is_tt_value(j));
assert(j["type"] == "date-local");
@ -86,7 +86,7 @@ TOML_NAMESPACE_START
from_json_via_parse(j, val);
}
void from_json(const json& j, value<time>& val)
static void from_json(const json& j, value<time>& val)
{
assert(is_tt_value(j));
assert(j["type"] == "time-local");
@ -94,7 +94,7 @@ TOML_NAMESPACE_START
from_json_via_parse(j, val);
}
void from_json(const json& j, value<date_time>& val)
static void from_json(const json& j, value<date_time>& val)
{
assert(is_tt_value(j));
assert(j["type"] == "datetime-local" || j["type"] == "datetime");
@ -102,7 +102,7 @@ TOML_NAMESPACE_START
from_json_via_parse(j, val);
}
void from_json(const json&, array&);
static void from_json(const json&, array&);
template <typename T, typename Key>
static void insert_from_json(table & tbl, Key && key, const json& val)
@ -120,7 +120,7 @@ TOML_NAMESPACE_START
arr.push_back(std::move(v));
}
void from_json(const json& j, table& tbl)
static void from_json(const json& j, table& tbl)
{
assert(j.is_object());
assert(!is_tt_value(j));
@ -154,7 +154,7 @@ TOML_NAMESPACE_START
}
}
void from_json(const json& j, array& arr)
static void from_json(const json& j, array& arr)
{
assert(j.is_array());

View File

@ -754,6 +754,12 @@
#define TOML_UNUSED(...) static_cast<void>(__VA_ARGS__)
#define TOML_DELETE_DEFAULTS(T) \
T(const T&) = delete; \
T(T&&) = delete; \
T& operator=(const T&) = delete; \
T& operator=(T&&) = delete
// SFINAE
#if defined(__cpp_concepts) && __cpp_concepts >= 201907
#define TOML_REQUIRES(...) requires(__VA_ARGS__)
@ -11393,10 +11399,7 @@ TOML_ANON_NAMESPACE_START
#endif
}
error_builder(const error_builder&) = delete;
error_builder(error_builder&&) = delete;
error_builder& operator=(const error_builder&) = delete;
error_builder& operator=(error_builder&&) = delete;
TOML_DELETE_DEFAULTS(error_builder);
};
struct parse_scope
@ -11417,16 +11420,13 @@ TOML_ANON_NAMESPACE_START
storage_ = parent_;
}
parse_scope(const parse_scope&) = delete;
parse_scope(parse_scope&&) = delete;
parse_scope& operator=(const parse_scope&) = delete;
parse_scope& operator=(parse_scope&&) = delete;
TOML_DELETE_DEFAULTS(parse_scope);
};
#define push_parse_scope_2(scope, line) parse_scope ps_##line(current_scope, scope)
#define push_parse_scope_1(scope, line) push_parse_scope_2(scope, line)
#define push_parse_scope(scope) push_parse_scope_1(scope, __LINE__)
struct parsed_key_buffer
struct parse_key_buffer
{
std::string buffer;
std::vector<std::pair<size_t, size_t>> segments;
@ -11474,25 +11474,23 @@ TOML_ANON_NAMESPACE_START
}
};
struct parse_depth_counter
struct depth_counter_scope
{
size_t& depth_;
TOML_NODISCARD_CTOR
explicit parse_depth_counter(size_t& depth) noexcept : depth_{ depth }
explicit depth_counter_scope(size_t& depth) noexcept //
: depth_{ depth }
{
depth_++;
}
~parse_depth_counter() noexcept
~depth_counter_scope() noexcept
{
depth_--;
}
parse_depth_counter(const parse_depth_counter&) = delete;
parse_depth_counter(parse_depth_counter&&) = delete;
parse_depth_counter& operator=(const parse_depth_counter&) = delete;
parse_depth_counter& operator=(parse_depth_counter&&) = delete;
TOML_DELETE_DEFAULTS(depth_counter_scope);
};
struct parsed_string
@ -11500,6 +11498,25 @@ TOML_ANON_NAMESPACE_START
std::string_view value;
bool was_multi_line;
};
struct table_vector_scope
{
std::vector<table*>& tables;
TOML_NODISCARD_CTOR
explicit table_vector_scope(std::vector<table*>& tables_, table& tbl) //
: tables{ tables_ }
{
tables.push_back(&tbl);
}
~table_vector_scope() noexcept
{
tables.pop_back();
}
TOML_DELETE_DEFAULTS(table_vector_scope);
};
}
TOML_ANON_NAMESPACE_END;
@ -11623,8 +11640,9 @@ TOML_IMPL_NAMESPACE_START
const utf8_codepoint* cp = {};
std::vector<table*> implicit_tables;
std::vector<table*> dotted_key_tables;
std::vector<table*> open_inline_tables;
std::vector<array*> table_arrays;
parsed_key_buffer key_buffer;
parse_key_buffer key_buffer;
std::string string_buffer;
std::string recording_buffer; // for diagnostics
bool recording = false, recording_whitespace = true;
@ -11648,10 +11666,7 @@ TOML_IMPL_NAMESPACE_START
void set_error_at(source_position pos, const T&... reason) const
{
static_assert(sizeof...(T) > 0);
#if !TOML_EXCEPTIONS
if (err)
return;
#endif
return_if_error();
error_builder builder{ current_scope };
(builder.append(reason), ...);
@ -13062,8 +13077,8 @@ TOML_IMPL_NAMESPACE_START
TOML_ASSERT_ASSUME(!is_value_terminator(*cp));
push_parse_scope("value"sv);
const parse_depth_counter depth_counter{ nested_values };
if (nested_values > max_nested_values)
const depth_counter_scope depth_counter{ nested_values };
if TOML_UNLIKELY(nested_values > max_nested_values)
set_error_and_return_default("exceeded maximum nested value depth of "sv,
static_cast<uint64_t>(max_nested_values),
" (TOML_MAX_NESTED_VALUES)"sv);
@ -13708,7 +13723,15 @@ TOML_IMPL_NAMESPACE_START
node& p = pit->second;
if (auto tbl = p.as_table())
{
// adding to closed inline tables is illegal
if (tbl->is_inline() && !impl::find(open_inline_tables.begin(), open_inline_tables.end(), tbl))
set_error_and_return_default("cannot insert '"sv,
to_sv(recording_buffer),
"' into existing inline table"sv);
parent = tbl;
}
else if (auto arr = p.as_array(); arr && impl::find(table_arrays.begin(), table_arrays.end(), arr))
{
// table arrays are a special case;
@ -13873,7 +13896,9 @@ TOML_IMPL_NAMESPACE_START
if (pit != tbl->end() && pit->first == segment)
{
table* p = pit->second.as_table();
if (!p
// redefinition
if TOML_UNLIKELY(!p
|| !(impl::find(dotted_key_tables.begin(), dotted_key_tables.end(), p)
|| impl::find(implicit_tables.begin(), implicit_tables.end(), p)))
{
@ -14132,6 +14157,8 @@ TOML_IMPL_NAMESPACE_START
node_ptr tbl_ptr{ new table{} };
table& tbl = tbl_ptr->ref_cast<table>();
tbl.is_inline(true);
table_vector_scope table_scope{ open_inline_tables, tbl };
enum TOML_CLOSED_ENUM parse_elem : int
{
none,
@ -14139,7 +14166,6 @@ TOML_IMPL_NAMESPACE_START
kvp
};
parse_elem prev = none;
while (!is_error())
{
if constexpr (TOML_LANG_UNRELEASED) // toml/issues/516 (newlines/trailing commas in inline tables)
@ -15599,6 +15625,7 @@ TOML_POP_WARNINGS;
#undef TOML_CONST_GETTER
#undef TOML_CONST_INLINE_GETTER
#undef TOML_CONSTRAINED_TEMPLATE
#undef TOML_DELETE_DEFAULTS
#undef TOML_DISABLE_ARITHMETIC_WARNINGS
#undef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
#undef TOML_DISABLE_SPAM_WARNINGS