mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-10 04:43:03 +00:00
Modern C++ (i.e., C++11 and later) introduced "move only" types: types such as std::unique_ptr<T> that can never be duplicated. They must never be copied (by assignments and constructors), they must be "moved". The implementation of lalr1.cc used to copy symbols (including their semantic values). This commit ensures that values are only moved in modern C++, yet remain compatible with C++98/C++03. Suggested by Frank Heckenbach, who provided a full implementation on top of C++17's std::variant. See http://lists.gnu.org/archive/html/bug-bison/2018-03/msg00002.html, and https://lists.gnu.org/archive/html/bison-patches/2018-04/msg00002.html. Symbols (terminal/non terminal) are handled by several functions that used to take const-refs, which resulted eventually in a copy pushed on the stack. With modern C++ (C++11 and later) the callers must use std::move, and the callees must take their arguments as rvalue refs (foo&&). In order to avoid duplicating these functions to support both legacy C++ and modern C++, let's introduce macros (YY_MOVE, YY_RVREF, etc.) that rely on copy-semantics for C++98/03, and move-semantics for modern C++. That's easy for inner types, when the parser's functions pass arguments to each other. Functions facing the user (make_NUMBER, make_STRING, etc.) should support both rvalue-refs (for instance to support move-only types: make_INT (std::make_unique<int> (1))), and lvalue-refs (so that we can pass a variable: make_INT (my_int)). To avoid the multiplication of the signatures (there is also the location), let's take the argument by value. See: https://lists.gnu.org/archive/html/bison-patches/2018-09/msg00024.html. * data/c++.m4 (b4_cxx_portability): New. (basic_symbol): In C++11, replace copy-ctors with move-ctors. In C++11, replace copies with moves. * data/lalr1.cc (stack_symbol_type, yypush_): Likewise. Use YY_MOVE to avoid useless copies. * data/variant.hh (variant): Support move-semantics. (make_SYMBOL): In C++11, in order to support both read-only lvalues, and rvalues, take the argument as a copy. * data/stack.hh (yypush_): Use rvalue-refs in C++11. * tests/c++.at: Use move semantics. * tests/headers.at: Adjust to the new macros (YY_MOVE, etc.). * configure.ac (CXX98_CXXFLAGS, CXX11_CXXFLAGS, CXX14_CXXFLAGS) (CXX17_CXXFLAGS, ENABLE_CXX11): New. * tests/atlocal.in: Receive them. * examples/variant.yy: Don't define things in std. * examples/variant-11.test, examples/variant-11.yy: New. Check the support of move-only types. * examples/README, examples/local.mk: Adjust.
380 lines
10 KiB
C++
380 lines
10 KiB
C++
# C++ skeleton for Bison
|
|
|
|
# Copyright (C) 2002-2015, 2018 Free Software Foundation, Inc.
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
## --------- ##
|
|
## variant. ##
|
|
## --------- ##
|
|
|
|
# b4_symbol_variant(YYTYPE, YYVAL, ACTION, [ARGS])
|
|
# ------------------------------------------------
|
|
# Run some ACTION ("build", or "destroy") on YYVAL of symbol type
|
|
# YYTYPE.
|
|
m4_define([b4_symbol_variant],
|
|
[m4_pushdef([b4_dollar_dollar],
|
|
[$2.$3< $][3 > (m4_shift3($@))])dnl
|
|
switch ($1)
|
|
{
|
|
b4_type_foreach([b4_type_action_])[]dnl
|
|
default:
|
|
break;
|
|
}
|
|
m4_popdef([b4_dollar_dollar])dnl
|
|
])
|
|
|
|
|
|
# _b4_char_sizeof_counter
|
|
# -----------------------
|
|
# A counter used by _b4_char_sizeof_dummy to create fresh symbols.
|
|
m4_define([_b4_char_sizeof_counter],
|
|
[0])
|
|
|
|
# _b4_char_sizeof_dummy
|
|
# ---------------------
|
|
# At each call return a new C++ identifier.
|
|
m4_define([_b4_char_sizeof_dummy],
|
|
[m4_define([_b4_char_sizeof_counter], m4_incr(_b4_char_sizeof_counter))dnl
|
|
dummy[]_b4_char_sizeof_counter])
|
|
|
|
|
|
# b4_char_sizeof(SYMBOL-NUMS)
|
|
# ---------------------------
|
|
# To be mapped on the list of type names to produce:
|
|
#
|
|
# char dummy1[sizeof(type_name_1)];
|
|
# char dummy2[sizeof(type_name_2)];
|
|
#
|
|
# for defined type names.
|
|
m4_define([b4_char_sizeof],
|
|
[b4_symbol_if([$1], [has_type],
|
|
[
|
|
m4_map([ b4_symbol_tag_comment], [$@])dnl
|
|
char _b4_char_sizeof_dummy@{sizeof(b4_symbol([$1], [type]))@};
|
|
])])
|
|
|
|
|
|
# b4_variant_includes
|
|
# -------------------
|
|
# The needed includes for variants support.
|
|
m4_define([b4_variant_includes],
|
|
[b4_parse_assert_if([[#include <typeinfo>]])[
|
|
#ifndef YYASSERT
|
|
# include <cassert>
|
|
# define YYASSERT assert
|
|
#endif
|
|
]])
|
|
|
|
# b4_variant_define
|
|
# -----------------
|
|
# Define "variant".
|
|
m4_define([b4_variant_define],
|
|
[[ /// A char[S] buffer to store and retrieve objects.
|
|
///
|
|
/// Sort of a variant, but does not keep track of the nature
|
|
/// of the stored data, since that knowledge is available
|
|
/// via the current state.
|
|
template <size_t S>
|
|
struct variant
|
|
{
|
|
/// Type of *this.
|
|
typedef variant<S> self_type;
|
|
|
|
/// Empty construction.
|
|
variant ()
|
|
: yybuffer_ ()]b4_parse_assert_if([
|
|
, yytypeid_ (YY_NULLPTR)])[
|
|
{}
|
|
|
|
/// Construct and fill.
|
|
template <typename T>
|
|
variant (YY_RVREF (T) t)]b4_parse_assert_if([
|
|
: yytypeid_ (&typeid (T))])[
|
|
{
|
|
YYASSERT (sizeof (T) <= S);
|
|
new (yyas_<T> ()) T (YY_MOVE (t));
|
|
}
|
|
|
|
/// Destruction, allowed only if empty.
|
|
~variant ()
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (!yytypeid_);
|
|
])[}
|
|
|
|
/// Instantiate an empty \a T in here.
|
|
template <typename T>
|
|
T&
|
|
build ()
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (!yytypeid_);
|
|
YYASSERT (sizeof (T) <= S);
|
|
yytypeid_ = & typeid (T);])[
|
|
return *new (yyas_<T> ()) T ();
|
|
}
|
|
|
|
/// Instantiate a \a T in here from \a t.
|
|
template <typename T>
|
|
T&
|
|
build (const T& t)
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (!yytypeid_);
|
|
YYASSERT (sizeof (T) <= S);
|
|
yytypeid_ = & typeid (T);])[
|
|
return *new (yyas_<T> ()) T (t);
|
|
}
|
|
|
|
/// Accessor to a built \a T.
|
|
template <typename T>
|
|
T&
|
|
as ()
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (yytypeid_);
|
|
YYASSERT (*yytypeid_ == typeid (T));
|
|
YYASSERT (sizeof (T) <= S);])[
|
|
return *yyas_<T> ();
|
|
}
|
|
|
|
/// Const accessor to a built \a T (for %printer).
|
|
template <typename T>
|
|
const T&
|
|
as () const
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (yytypeid_);
|
|
YYASSERT (*yytypeid_ == typeid (T));
|
|
YYASSERT (sizeof (T) <= S);])[
|
|
return *yyas_<T> ();
|
|
}
|
|
|
|
/// Swap the content with \a other, of same type.
|
|
///
|
|
/// Both variants must be built beforehand, because swapping the actual
|
|
/// data requires reading it (with as()), and this is not possible on
|
|
/// unconstructed variants: it would require some dynamic testing, which
|
|
/// should not be the variant's responsability.
|
|
/// Swapping between built and (possibly) non-built is done with
|
|
/// variant::move ().
|
|
template <typename T>
|
|
void
|
|
swap (self_type& other)
|
|
{]b4_parse_assert_if([
|
|
YYASSERT (yytypeid_);
|
|
YYASSERT (*yytypeid_ == *other.yytypeid_);])[
|
|
std::swap (as<T> (), other.as<T> ());
|
|
}
|
|
|
|
/// Move the content of \a other to this.
|
|
///
|
|
/// Destroys \a other.
|
|
template <typename T>
|
|
void
|
|
move (self_type& other)
|
|
{
|
|
build<T> ();
|
|
# if defined __cplusplus && 201103L <= __cplusplus
|
|
as<T> () = YY_MOVE (other.as<T> ());
|
|
# else
|
|
swap<T> (other);
|
|
# endif
|
|
other.destroy<T> ();
|
|
}
|
|
|
|
# if defined __cplusplus && 201103L <= __cplusplus
|
|
/// Move the content of \a other to this.
|
|
template <typename T>
|
|
void
|
|
move (self_type&& other)
|
|
{
|
|
build<T> ();
|
|
as<T> () = YY_MOVE (other.as<T> ());
|
|
other.destroy<T> ();
|
|
}
|
|
#endif
|
|
|
|
/// Copy the content of \a other to this.
|
|
template <typename T>
|
|
void
|
|
copy (const self_type& other)
|
|
{
|
|
build<T> (other.as<T> ());
|
|
}
|
|
|
|
/// Destroy the stored \a T.
|
|
template <typename T>
|
|
void
|
|
destroy ()
|
|
{
|
|
as<T> ().~T ();]b4_parse_assert_if([
|
|
yytypeid_ = YY_NULLPTR;])[
|
|
}
|
|
|
|
private:
|
|
/// Prohibit blind copies.
|
|
self_type& operator=(const self_type&);
|
|
variant (const self_type&);
|
|
|
|
/// Accessor to raw memory as \a T.
|
|
template <typename T>
|
|
T*
|
|
yyas_ ()
|
|
{
|
|
void *yyp = yybuffer_.yyraw;
|
|
return static_cast<T*> (yyp);
|
|
}
|
|
|
|
/// Const accessor to raw memory as \a T.
|
|
template <typename T>
|
|
const T*
|
|
yyas_ () const
|
|
{
|
|
const void *yyp = yybuffer_.yyraw;
|
|
return static_cast<const T*> (yyp);
|
|
}
|
|
|
|
union
|
|
{
|
|
/// Strongest alignment constraints.
|
|
long double yyalign_me;
|
|
/// A buffer large enough to store any of the semantic values.
|
|
char yyraw[S];
|
|
} yybuffer_;]b4_parse_assert_if([
|
|
|
|
/// Whether the content is built: if defined, the name of the stored type.
|
|
const std::type_info *yytypeid_;])[
|
|
};
|
|
]])
|
|
|
|
|
|
## -------------------------- ##
|
|
## Adjustments for variants. ##
|
|
## -------------------------- ##
|
|
|
|
|
|
# b4_value_type_declare
|
|
# ---------------------
|
|
# Declare semantic_type.
|
|
m4_define([b4_value_type_declare],
|
|
[[ /// An auxiliary type to compute the largest semantic type.
|
|
union union_type
|
|
{]b4_type_foreach([b4_char_sizeof])[};
|
|
|
|
/// Symbol semantic values.
|
|
typedef variant<sizeof(union_type)> semantic_type;][]dnl
|
|
])
|
|
|
|
|
|
# How the semantic value is extracted when using variants.
|
|
|
|
# b4_symbol_value(VAL, [TYPE])
|
|
# ----------------------------
|
|
m4_define([b4_symbol_value],
|
|
[m4_ifval([$2],
|
|
[$1.as< $2 > ()],
|
|
[$1])])
|
|
|
|
# b4_symbol_value_template(VAL, [TYPE])
|
|
# -------------------------------------
|
|
# Same as b4_symbol_value, but used in a template method.
|
|
m4_define([b4_symbol_value_template],
|
|
[m4_ifval([$2],
|
|
[$1.template as< $2 > ()],
|
|
[$1])])
|
|
|
|
|
|
|
|
## ------------- ##
|
|
## make_SYMBOL. ##
|
|
## ------------- ##
|
|
|
|
|
|
# b4_symbol_constructor_declare_(SYMBOL-NUMBER)
|
|
# ---------------------------------------------
|
|
# Declare the overloaded version of make_symbol for the (common) type of
|
|
# these SYMBOL-NUMBERS. Use at class-level.
|
|
m4_define([b4_symbol_constructor_declare_],
|
|
[b4_symbol_if([$1], [is_token], [b4_symbol_if([$1], [has_id],
|
|
[ static
|
|
symbol_type
|
|
make_[]b4_symbol_([$1], [id]) (dnl
|
|
b4_join(b4_symbol_if([$1], [has_type],
|
|
[YY_COPY (b4_symbol([$1], [type])) v]),
|
|
b4_locations_if([YY_COPY (location_type) l])));
|
|
|
|
])])])
|
|
|
|
|
|
# b4_symbol_constructor_declare
|
|
# -----------------------------
|
|
# Declare symbol constructors for all the value types.
|
|
# Use at class-level.
|
|
m4_define([b4_symbol_constructor_declare],
|
|
[ // Symbol constructors declarations.
|
|
b4_symbol_foreach([b4_symbol_constructor_declare_])])
|
|
|
|
|
|
|
|
# b4_symbol_constructor_define_(SYMBOL-NUMBER)
|
|
# --------------------------------------------
|
|
# Define symbol constructor for this SYMBOL-NUMBER.
|
|
m4_define([b4_symbol_constructor_define_],
|
|
[b4_symbol_if([$1], [is_token], [b4_symbol_if([$1], [has_id],
|
|
[ inline
|
|
b4_parser_class_name::symbol_type
|
|
b4_parser_class_name::make_[]b4_symbol_([$1], [id]) (dnl
|
|
b4_join(b4_symbol_if([$1], [has_type],
|
|
[YY_COPY (b4_symbol([$1], [type])) v]),
|
|
b4_locations_if([YY_COPY (location_type) l])))
|
|
{
|
|
return symbol_type (b4_join([token::b4_symbol([$1], [id])],
|
|
b4_symbol_if([$1], [has_type], [YY_MOVE (v)]),
|
|
b4_locations_if([YY_MOVE (l)])));
|
|
}
|
|
|
|
])])])
|
|
|
|
|
|
# b4_basic_symbol_constructor_declare
|
|
# -----------------------------------
|
|
# Generate a constructor declaration for basic_symbol from given type.
|
|
m4_define([b4_basic_symbol_constructor_declare],
|
|
[[ basic_symbol (]b4_join(
|
|
[typename Base::kind_type t],
|
|
b4_symbol_if([$1], [has_type], [YY_RVREF (b4_symbol([$1], [type])) v]),
|
|
b4_locations_if([YY_RVREF (location_type) l]))[);
|
|
]])
|
|
|
|
# b4_basic_symbol_constructor_define
|
|
# ----------------------------------
|
|
# Generate a constructor implementation for basic_symbol from given type.
|
|
m4_define([b4_basic_symbol_constructor_define],
|
|
[[ template <typename Base>
|
|
]b4_parser_class_name[::basic_symbol<Base>::basic_symbol (]b4_join(
|
|
[typename Base::kind_type t],
|
|
b4_symbol_if([$1], [has_type], [YY_RVREF (b4_symbol([$1], [type])) v]),
|
|
b4_locations_if([YY_RVREF (location_type) l]))[)
|
|
: Base (t)]b4_symbol_if([$1], [has_type], [
|
|
, value (YY_MOVE (v))])[]b4_locations_if([
|
|
, location (YY_MOVE (l))])[
|
|
{}
|
|
|
|
]])
|
|
|
|
# b4_symbol_constructor_define
|
|
# ----------------------------
|
|
# Define the overloaded versions of make_symbol for all the value types.
|
|
m4_define([b4_symbol_constructor_define],
|
|
[ // Implementation of make_symbol for each symbol type.
|
|
b4_symbol_foreach([b4_symbol_constructor_define_])])
|