bison-patches
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]