[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 3/5] c++: introduce api.value.automove
From: |
Akim Demaille |
Subject: |
[PATCH 3/5] c++: introduce api.value.automove |
Date: |
Sat, 22 Sep 2018 12:53:22 +0200 |
Based on work by Frank Heckenbach.
See http://lists.gnu.org/archive/html/bug-bison/2018-04/msg00000.html
and http://lists.gnu.org/archive/html/bug-bison/2018-09/msg00019.html.
* data/lalr1.cc (b4_rhs_value): Use YY_MOVE api.rhs.automove is set.
* doc/bison.texi (%define Summary): Document api.rhs.automove.
* examples/variant-11.yy: Use it.
* tests/local.at (AT_AUTOMOVE_IF): New.
* tests/c++.at (Variants): Check move semantics.
---
data/lalr1.cc | 7 ++++-
doc/bison.texi | 60 +++++++++++++++++++++++++++++++++++
examples/variant-11.yy | 5 +--
tests/c++.at | 71 +++++++++++++++++++++++++++++++++++++++++-
tests/local.at | 2 ++
5 files changed, 141 insertions(+), 4 deletions(-)
diff --git a/data/lalr1.cc b/data/lalr1.cc
index 1a5138bf..eb4d6ca0 100644
--- a/data/lalr1.cc
+++ b/data/lalr1.cc
@@ -83,9 +83,14 @@ m4_define([b4_rhs_state],
# --------------------------------------
# Expansion of $<TYPE>NUM, where the current rule has RULE-LENGTH
# symbols on RHS.
-m4_define([b4_rhs_value],
+m4_define([_b4_rhs_value],
[b4_symbol_value([b4_rhs_data([$1], [$2]).value], [$3])])
+m4_define([b4_rhs_value],
+[b4_percent_define_ifdef([api.value.automove],
+ [YY_MOVE(_b4_rhs_value($@))],
+ [_b4_rhs_value($@)])])
+
# b4_rhs_location(RULE-LENGTH, NUM)
# ---------------------------------
diff --git a/doc/bison.texi b/doc/bison.texi
index e486c213..3620c60f 100644
--- a/doc/bison.texi
+++ b/doc/bison.texi
@@ -5982,6 +5982,66 @@ introduced in Bison 3.0
@c api.token.prefix
address@hidden ==================================================
api.value.automove
address@hidden Directive {%define api.value.automove}
+
address@hidden @bullet
address@hidden Language(s):
+C++
+
address@hidden Purpose:
+Let occurrences of semantic values of the right-hand sides of a rule be
+implicitly turned in rvalues. When enabled, a grammar such as:
+
address@hidden
+exp:
+ "number" @{ $$ = make_number ($1); @}
+| exp "+" exp @{ $$ = make_binary (add, $1, $3); @}
+| "(" exp ")" @{ $$ = $2; @}
address@hidden example
+
address@hidden
+is actually compiled as if you had written:
+
address@hidden
+exp:
+ "number" @{ $$ = make_number (std::move ($1)); @}
+| exp "+" exp @{ $$ = make_binary (add,
+ std::move ($1),
+ std::move ($3)); @}
+| "(" exp ")" @{ $$ = std::move ($2); @}
address@hidden example
+
+Using a value several times with automove enabled is typically an error.
+For instance, instead of:
+
address@hidden
+exp: "twice" exp @{ $$ = make_binary (add, $2, $2); @}
address@hidden example
+
address@hidden
+write:
+
address@hidden
+exp: "twice" exp @{ auto v = $2; $$ = make_binary (add, v, v); @}
address@hidden example
+
address@hidden
+It is tempting to use @code{std::move} on one of the @code{v}, but the
+argument evaluation order in C++ is unspecified.
+
address@hidden Accepted Values:
+Boolean.
+
address@hidden Default Value:
address@hidden
address@hidden History:
+introduced in Bison 3.2
address@hidden itemize
address@hidden deffn
address@hidden api.value.automove
+
+
@c ================================================== api.value.type
@deffn Directive {%define api.value.type} @var{support}
@deffnx Directive {%define api.value.type} @address@hidden@}
diff --git a/examples/variant-11.yy b/examples/variant-11.yy
index c78bab07..81b0b1b9 100644
--- a/examples/variant-11.yy
+++ b/examples/variant-11.yy
@@ -20,6 +20,7 @@
%defines
%define api.token.constructor
%define api.value.type variant
+%define api.value.automove
%define parse.assert
%locations
@@ -96,11 +97,11 @@ result:
list:
%empty { /* Generates an empty string list */ }
-| list item { $$ = std::move ($1); $$.emplace_back (std::move ($2)); }
+| list item { $$ = $1; $$.emplace_back ($2); }
;
item:
- TEXT { $$ = std::move ($1); }
+ TEXT { $$ = $1; }
| NUMBER { $$ = make_string_uptr (to_string ($1)); }
;
%%
diff --git a/tests/c++.at b/tests/c++.at
index d6cca694..780a8415 100644
--- a/tests/c++.at
+++ b/tests/c++.at
@@ -241,6 +241,21 @@ AT_DATA_GRAMMAR([list.y],
return *this;
}
+#if defined __cplusplus && 201103L <= __cplusplus
+ string (string&& s)
+ : val_(std::move(s.val_))
+ {
+ s.val_.clear();
+ }
+
+ string& operator= (string&& s)
+ {
+ val_ = std::move(s.val_);
+ s.val_.clear ();
+ return *this;
+ }
+#endif
+
friend
std::ostream& operator<< (std::ostream& o, const string& s)
{
@@ -384,9 +399,60 @@ namespace yy
]AT_MAIN_DEFINE[
]])
+AT_DATA_SOURCE([[modern.cc]],
+[[#include <iostream>
+int main()
+{
+#if defined __cplusplus && 201103L <= __cplusplus
+ std::cout << "Modern C++: " << __cplusplus << '\n';
+ return 0;
+#else
+ std::cout << "Legac++\n";
+ return 1;
+#endif
+}
+]])
+
AT_FOR_EACH_CXX([
AT_FULL_COMPILE([list])
-AT_PARSER_CHECK([./list], 0,
+
+# Are we compiling with modern C++ enabled?
+AT_COMPILE_CXX([modern])
+AT_CHECK([./modern], [ignore], [ignore])
+if test $at_status = 0; then
+ modern=true
+else
+ modern=false
+fi
+
+if AT_AUTOMOVE_IF([$modern], [false]); then
+ AT_PARSER_CHECK([./list], 0,
+[[(0, 1, 2, 4, 6)
+]],
+[[Destroy: ""
+Destroy: ""
+Destroy: 1
+Destroy: ""
+Destroy: ()
+Destroy: ""
+Destroy: ""
+Destroy: ()
+Destroy: ""
+Destroy: 3
+Destroy: ()
+Destroy: ""
+Destroy: ""
+Destroy: ()
+Destroy: ()
+Destroy: 5
+Destroy: ()
+Destroy: ""
+Destroy: ""
+Destroy: ()
+Destroy: (0, 1, 2, 4, 6)
+]])
+else
+ AT_PARSER_CHECK([./list], 0,
[[(0, 1, 2, 4, 6)
]],
[[Destroy: "0"
@@ -411,6 +477,7 @@ Destroy: "6"
Destroy: (0, 1, 2, 4)
Destroy: (0, 1, 2, 4, 6)
]])
+fi
])
AT_BISON_OPTION_POPDEFS
@@ -419,11 +486,13 @@ AT_CLEANUP
AT_TEST([[%skeleton "lalr1.cc"]])
AT_TEST([[%skeleton "lalr1.cc" %define parse.assert]])
+AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %define
api.value.automove]])
AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %locations]])
AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %code {\n#define
TWO_STAGE_BUILD\n}]])
AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %define
api.token.constructor]])
AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %define
api.token.constructor %define api.token.prefix {TOK_}]])
AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %define
api.token.constructor %define api.token.prefix {TOK_} %locations]])
+AT_TEST([[%skeleton "lalr1.cc" %define parse.assert %define
api.token.constructor %define api.token.prefix {TOK_} %locations %define
api.value.automove]])
m4_popdef([AT_TEST])
diff --git a/tests/local.at b/tests/local.at
index 56f8e11a..9a0bec15 100644
--- a/tests/local.at
+++ b/tests/local.at
@@ -139,6 +139,8 @@ m4_define([AT_BISON_OPTION_PUSHDEFS],
m4_define([_AT_BISON_OPTION_PUSHDEFS],
[m4_if([$1$2], $[1]$[2], [],
[m4_fatal([$0: Invalid arguments: address@hidden)])dnl
+m4_pushdef([AT_AUTOMOVE_IF],
+[m4_bmatch([$3], [%define api\.value\.automove], [$1], [$2])])
m4_pushdef([AT_DEFINES_IF],
[m4_bmatch([$3], [%defines], [$1], [$2])])
m4_pushdef([AT_DEBUG_IF],
--
2.19.0
- RFC: api.value.automove, Akim Demaille, 2018/09/19
- Re: RFC: api.value.automove, Hans Ã…berg, 2018/09/19
- Re: RFC: api.value.automove, Frank Heckenbach, 2018/09/20
- Re: RFC: api.value.automove, Akim Demaille, 2018/09/21
- Re: RFC: api.value.automove, Frank Heckenbach, 2018/09/21
- [PATCH 0/5] lalr1.cc: automove, Akim Demaille, 2018/09/22
- [PATCH 1/5] tests: prepare a test for automove, Akim Demaille, 2018/09/22
- [PATCH 2/5] tests: c++: use a custom string type, Akim Demaille, 2018/09/22
- [PATCH 3/5] c++: introduce api.value.automove,
Akim Demaille <=
- [PATCH 4/5] c++: issue a warning with a value is moved several times, Akim Demaille, 2018/09/22
- [PATCH 5/5] news: c++: move semantics, Akim Demaille, 2018/09/22