[RFC,libstdc++] Implement C++20 P1208R6 - source_location.
diff mbox series

Message ID 71d6be45-bf71-2df4-4838-9bf092c234be@verizon.net
State New
Headers show
Series
  • [RFC,libstdc++] Implement C++20 P1208R6 - source_location.
Related show

Commit Message

Ian Lance Taylor via gcc-patches Nov. 8, 2019, 11:12 p.m. UTC
As an experiment, I took a shot at implementing source_location for 
C++20.?? This was mostly done in experimental but I wanted to try adding 
column information.?? (The experimental version just returned 0).?? I 
added __builtin_COLUMN in analogy to __builtin_LINE.?? The std version is 
also consteval so you get different results in some cases wrt 
experimental. You can diff the two 1.cc test cases in libstdc++ to see 
for yourself.

As Jonathan mentioned on IRC, we probably want a single builtin and we 
want to coordinate the name with clang (__builtin_source_location?).?? 
But this "works" and it might make useful fodder for the next round.

Ed
gcc/ChangeLog

2019-11-08  Ed Smith-Rowland  <3dw4rd@verizon.net>

	Implement C++20 P1208R6 - source_location.  Implement column with a
	__builtin_COLUMN for both std and experimental.  The std current()
	is consteval.
	* builtins.c (fold_builtin_COLUMN): New function.
	(fold_builtin_0): Use it.
	* builtins.def: Add __builtin_COLUMN.
	* doc/extend.texi: Doc __builtin_COLUMN.
	* testsuite/c-c++-common/builtin_location.c: __builtin_COLUMN() tests.
	* testsuite/c-c++-common/cpp/has-builtin-2.c: __builtin_COLUMN test.


libstdc++-v3/ChangeLog

2019-11-08  Ed Smith-Rowland  <3dw4rd@verizon.net>

	Implement C++20 P1208R6 - source_location.  Implement column with a
	__builtin_COLUMN for both std and experimental.  The std current()
	is consteval.
	* include/experimental/source_location: Call __builtin_COLUMN
	* include/std/source_location: New header.
	* include/std/version: Add <source_location>
	* testsuite/20_util/source_location/1.cc: New test.
	* libstdc++-v3/testsuite/experimental/source_location/1.cc: Test column.

Comments

Jonathan Wakely Nov. 14, 2019, 3:56 p.m. UTC | #1
On 08/11/19 18:12 -0500, Ed Smith-Rowland wrote:
>As an experiment, I took a shot at implementing source_location for 
>C++20.?? This was mostly done in experimental but I wanted to try 
>adding column information.?? (The experimental version just returned 
>0).?? I added __builtin_COLUMN in analogy to __builtin_LINE.?? The std 
>version is also consteval so you get different results in some cases 
>wrt experimental. You can diff the two 1.cc test cases in libstdc++ to 
>see for yourself.
>
>As Jonathan mentioned on IRC, we probably want a single builtin and we 
>want to coordinate the name with clang (__builtin_source_location?).?? 
>But this "works" and it might make useful fodder for the next round.

Yes, I don't think we want to implement std::source_location this way
if we know we're going to change its layout later. But if the
__builtin_COLUMN part is approved then we could start using it in
std::experimental::source_location right away.

Patch
diff mbox series

Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c	(revision 277745)
+++ gcc/builtins.c	(working copy)
@@ -9500,6 +9500,14 @@ 
   return build_int_cst (type, LOCATION_LINE (loc));
 }
 
+/* Fold a call to __builtin_COLUMN to an integer constant.  */
+
+static inline tree
+fold_builtin_COLUMN (location_t loc, tree type)
+{
+  return build_int_cst (type, LOCATION_COLUMN (loc));
+}
+
 /* Fold a call to built-in function FNDECL with 0 arguments.
    This function returns NULL_TREE if no simplification was possible.  */
 
@@ -9519,6 +9527,9 @@ 
     case BUILT_IN_LINE:
       return fold_builtin_LINE (loc, type);
 
+    case BUILT_IN_COLUMN:
+      return fold_builtin_COLUMN (loc, type);
+
     CASE_FLT_FN (BUILT_IN_INF):
     CASE_FLT_FN_FLOATN_NX (BUILT_IN_INF):
     case BUILT_IN_INFD32:
Index: gcc/builtins.def
===================================================================
--- gcc/builtins.def	(revision 277745)
+++ gcc/builtins.def	(working copy)
@@ -1048,6 +1048,7 @@ 
 DEF_GCC_BUILTIN (BUILT_IN_FILE, "FILE", BT_FN_CONST_STRING, ATTR_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN (BUILT_IN_FUNCTION, "FUNCTION", BT_FN_CONST_STRING, ATTR_NOTHROW_LEAF_LIST)
 DEF_GCC_BUILTIN (BUILT_IN_LINE, "LINE", BT_FN_INT, ATTR_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN (BUILT_IN_COLUMN, "COLUMN", BT_FN_INT, ATTR_NOTHROW_LEAF_LIST)
 
 /* Synchronization Primitives.  */
 #include "sync-builtins.def"
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 277745)
+++ gcc/doc/extend.texi	(working copy)
@@ -13154,6 +13154,13 @@ 
 of the call to @var{F}.
 @end deftypefn
 
+@deftypefn {Built-in Function} int __builtin_COLUMN ()
+This function returns a constant integer expression that evaluates to
+the column number of the invocation of the built-in.  When used as a C++
+default argument for a function @var{F}, it returns the line number
+of the call to @var{F}.
+@end deftypefn
+
 @deftypefn {Built-in Function} {const char *} __builtin_FUNCTION ()
 This function is the equivalent of the @code{__FUNCTION__} symbol
 and returns an address constant pointing to the name of the function
Index: libstdc++-v3/include/experimental/source_location
===================================================================
--- libstdc++-v3/include/experimental/source_location	(revision 277745)
+++ libstdc++-v3/include/experimental/source_location	(working copy)
@@ -52,7 +52,7 @@ 
     current(const char* __file = __builtin_FILE(),
 	    const char* __func = __builtin_FUNCTION(),
 	    int __line = __builtin_LINE(),
-	    int __col = 0) noexcept
+	    int __col = __builtin_COLUMN()) noexcept
     {
       source_location __loc;
       __loc._M_file = __file;
Index: libstdc++-v3/include/std/source_location
===================================================================
--- libstdc++-v3/include/std/source_location	(nonexistent)
+++ libstdc++-v3/include/std/source_location	(working copy)
@@ -0,0 +1,95 @@ 
+// <source_location> -*- C++ -*-
+
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library 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, or (at your option)
+// any later version.
+
+// This library 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/source_location
+ *  This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_SOURCE_LOCATION
+#define _GLIBCXX_SOURCE_LOCATION 1
+
+#include <cstdint>
+
+namespace std {
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#define __cpp_lib_source_location 201907L
+
+  struct source_location
+  {
+#ifndef _GLIBCXX_USE_C99_STDINT_TR1
+  private:
+    using uint_least32_t = unsigned;
+  public:
+#endif
+
+    // source_location creation
+
+    static consteval source_location
+    current(const char* __file = __builtin_FILE(),
+	    const char* __func = __builtin_FUNCTION(),
+	    int __line = __builtin_LINE(),
+	    int __col = __builtin_COLUMN()) noexcept
+    {
+      source_location __loc;
+      __loc._M_file = __file;
+      __loc._M_func = __func;
+      __loc._M_line = __line;
+      __loc._M_col = __col;
+      return __loc;
+    }
+
+    constexpr source_location() noexcept
+    : _M_file("unknown"), _M_func(_M_file), _M_line(0), _M_col(0)
+    { }
+
+    // source_location field access
+
+    constexpr uint_least32_t
+    line() const noexcept
+    { return this->_M_line; }
+
+    constexpr uint_least32_t
+    column() const noexcept
+    { return this->_M_col; }
+
+    constexpr const char*
+    file_name() const noexcept
+    { return this->_M_file; }
+
+    constexpr const char*
+    function_name() const noexcept
+    { return this->_M_func; }
+
+  private:
+    const char* _M_file;
+    const char* _M_func;
+    uint_least32_t _M_line;
+    uint_least32_t _M_col;
+  };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // _GLIBCXX_SOURCE_LOCATION
Index: libstdc++-v3/include/std/version
===================================================================
--- libstdc++-v3/include/std/version	(revision 277745)
+++ libstdc++-v3/include/std/version	(working copy)
@@ -173,6 +173,7 @@ 
 #define __cpp_lib_math_constants 201907L
 #define __cpp_lib_span 201902L
 #define __cpp_lib_to_array 201907L
+#define __cpp_lib_source_location 201907L
 #endif // C++2a
 #endif // C++17
 #endif // C++14
Index: libstdc++-v3/testsuite/20_util/source_location/1.cc
===================================================================
--- libstdc++-v3/testsuite/20_util/source_location/1.cc	(nonexistent)
+++ libstdc++-v3/testsuite/20_util/source_location/1.cc	(working copy)
@@ -0,0 +1,118 @@ 
+// Copyright (C) 2019 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library 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, or (at your option)
+// any later version.
+
+// This library 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 library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++2a } }
+// { dg-require-cstdint "" }
+#include <cassert>
+#include <source_location>
+#include <string_view>
+#include <iostream>
+#include <testsuite_hooks.h>
+using std::source_location;
+using std::string_view;
+
+void
+test01()
+{
+  constexpr source_location loc = source_location::current();
+  static_assert( loc.line() == 31 );
+  static_assert( loc.column() == 60 );
+  static_assert( loc.file_name() == __FILE__ );
+  static_assert( loc.function_name() == __FUNCTION__ );
+}
+
+struct S {
+  string_view func;
+  source_location loc = source_location::current();
+
+  S(source_location loc = source_location::current())
+  : func(__FUNCTION__), loc(loc) // Values of loc will be from call-site.
+  {}
+
+  S(int)
+  : func(__FUNCTION__) // Values of loc should be at the NSDMI above.
+  {}
+};
+
+void test02()
+{
+  S s0;
+  VERIFY( s0.loc.line() == 42 );
+  VERIFY( s0.loc.column() == 52 );
+  VERIFY( s0.loc.file_name() == __FILE__ );
+  VERIFY( s0.loc.function_name() == "" ); // Not inside ctor.
+
+  S s1(1);
+  VERIFY( s1.loc.line() == 40 );
+  VERIFY( s1.loc.file_name() == __FILE__ );
+  VERIFY( s1.loc.function_name() == "" ); // No function, class member.
+}
+
+source_location f(source_location a = source_location::current()) {
+  return a;
+}
+
+source_location g(string_view& func) {
+  source_location a = source_location::current();
+  func = __FUNCTION__;
+  return a;
+}
+
+void test03()
+{
+  auto loc = f(); // f's first argument corresponds to the definition above
+  VERIFY( loc.line() == 65 );
+  VERIFY( loc.column() == 64 );
+  VERIFY( loc.file_name() == __FILE__ );
+  VERIFY( loc.function_name() == "" );
+
+  source_location c = source_location::current();
+  loc = f(c); // f's first argument gets the same values as c, above
+  VERIFY( loc.line() == 83 );
+  VERIFY( loc.column() == 48 );
+  VERIFY( loc.file_name() == __FILE__ );
+  VERIFY( loc.function_name() == __FUNCTION__ );
+
+  string_view func;
+  loc = g(func);
+  VERIFY( loc.line() == 70 );
+  VERIFY( loc.column() == 48 );
+  VERIFY( loc.file_name() == __FILE__ );
+  VERIFY( loc.function_name() == func );
+}
+
+void
+test04()
+{
+  using std::is_same_v;
+  using std::uint_least32_t;
+  auto loc = source_location::current();
+  static_assert(is_same_v<decltype(loc), source_location>);
+  static_assert(is_same_v<decltype(loc.line()), uint_least32_t>);
+  static_assert(is_same_v<decltype(loc.column()), uint_least32_t>);
+  static_assert(is_same_v<decltype(loc.file_name()), const char*>);
+  static_assert(is_same_v<decltype(loc.function_name()), const char*>);
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+  test04();
+}
Index: libstdc++-v3/testsuite/experimental/source_location/1.cc
===================================================================
--- libstdc++-v3/testsuite/experimental/source_location/1.cc	(revision 277745)
+++ libstdc++-v3/testsuite/experimental/source_location/1.cc	(working copy)
@@ -30,7 +30,7 @@ 
 {
   constexpr source_location loc = source_location::current();
   static_assert( loc.line() == 31 );
-  // static_assert( loc.column() == 35 );
+  static_assert( loc.column() == 60 );
   VERIFY( loc.file_name() == __FILE__ );
   VERIFY( loc.function_name() == string_view(__FUNCTION__) );
 }
@@ -52,7 +52,7 @@ 
 {
   S s0;
   VERIFY( s0.loc.line() == 53 );
-  // static_assert( s0.loc.column() == 7 );
+  VERIFY( s0.loc.column() == 5 );
   VERIFY( s0.loc.file_name() == __FILE__ );
   VERIFY( s0.loc.function_name() == string_view(__FUNCTION__) );
 
@@ -76,7 +76,7 @@ 
 {
   auto loc = f(); // f's first argument corresponds to this line of code
   VERIFY( loc.line() == 77 );
-  // static_assert( loc.column() == 16 );
+  VERIFY( loc.column() == 16 );
   VERIFY( loc.file_name() == __FILE__ );
   VERIFY( loc.function_name() == string_view(__FUNCTION__) );
 
@@ -83,7 +83,7 @@ 
   source_location c = source_location::current();
   loc = f(c); // f's first argument gets the same values as c, above
   VERIFY( loc.line() == 83 );
-  // static_assert( loc.column() == 23 );
+  VERIFY( loc.column() == 48 );
   VERIFY( loc.file_name() == __FILE__ );
   VERIFY( loc.function_name() == string_view(__FUNCTION__) );
 
@@ -90,7 +90,7 @@ 
   string_view func;
   loc = g(func);
   VERIFY( loc.line() == 70 );
-  // static_assert( loc.column() == 23 );
+  VERIFY( loc.column() == 48 );
   VERIFY( loc.file_name() == __FILE__ );
   VERIFY( loc.function_name() == func );
 }
Index: gcc/testsuite/c-c++-common/builtin_location.c
===================================================================
--- gcc/testsuite/c-c++-common/builtin_location.c	(revision 277745)
+++ gcc/testsuite/c-c++-common/builtin_location.c	(working copy)
@@ -55,3 +55,11 @@ 
 struct S { unsigned bitfield: __builtin_LINE (); } s;
 
 Assert (__builtin_constant_p (__builtin_LINE ()));
+
+/* Verify that __builtin_COLUMN () yields an integer constant expression.  */
+#line 23
+int aC [__builtin_COLUMN ()][__builtin_COLUMN ()];
+enum FC { f0 = __builtin_LINE () };
+struct SC { unsigned bitfield: __builtin_COLUMN (); } s;
+
+Assert (__builtin_constant_p (__builtin_COLUMN ()));
Index: gcc/testsuite/c-c++-common/cpp/has-builtin-2.c
===================================================================
--- gcc/testsuite/c-c++-common/cpp/has-builtin-2.c	(revision 277745)
+++ gcc/testsuite/c-c++-common/cpp/has-builtin-2.c	(working copy)
@@ -64,6 +64,10 @@ 
 #  error "__has_builtin (__builtin_LINE) failed"
 #endif
 
+#if !__has_builtin (__builtin_COLUMN)
+#  error "__has_builtin (__builtin_COLUMN) failed"
+#endif
+
 #if !__has_builtin (__builtin_object_size)
 #  error "__has_builtin (__builtin_object_size) failed"
 #endif