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 <3dw...@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 <3dw...@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.
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