diff mbox series

[C++,libstdc++] P1208r6 Merge source_location

Message ID CANHA4Oiog-fEJszB+kf4WbTux5WtFfbZ4OpWUxdJhGBoPV=BEQ@mail.gmail.com
State New
Headers show
Series [C++,libstdc++] P1208r6 Merge source_location | expand

Commit Message

JeanHeyd Meneide Dec. 27, 2019, 7:27 p.m. UTC
This patch implements std::source_location. There's a couple
cases where the builtin implemented does not do what is expected of
it, and so the bottom 3 batches of test cases fails. I'm still
including the patch so that others can pick up on what might need to
change about the __builtin_source_location implementation (CC:
Jonathan Wakely, Jakub Jelinek).

2019-12-27  JeanHeyd "ThePhD" Meneide  <phdofthehouse@gmail.com>

        * include/Makefile.in: add source_location header
        * include/bits/c++config: Add new detection macros for
          LINE, COLUMN, and SOURCE_LOCATION builtins.
        * include/std/source_location: New.
        * testuite/std/support/srcloc/std.n4842.C (new): test source_location
        * testuite/std/support/srcloc/std.n4842.h (new): test source_location

Comments

Jakub Jelinek Dec. 27, 2019, 7:33 p.m. UTC | #1
On Fri, Dec 27, 2019 at 02:27:12PM -0500, JeanHeyd Meneide wrote:
>      This patch implements std::source_location. There's a couple
> cases where the builtin implemented does not do what is expected of
> it, and so the bottom 3 batches of test cases fails. I'm still
> including the patch so that others can pick up on what might need to
> change about the __builtin_source_location implementation (CC:
> Jonathan Wakely, Jakub Jelinek).
> 
> 2019-12-27  JeanHeyd "ThePhD" Meneide  <phdofthehouse@gmail.com>
> 
>         * include/Makefile.in: add source_location header
>         * include/bits/c++config: Add new detection macros for
>           LINE, COLUMN, and SOURCE_LOCATION builtins.
>         * include/std/source_location: New.
>         * testuite/std/support/srcloc/std.n4842.C (new): test source_location
>         * testuite/std/support/srcloc/std.n4842.h (new): test source_location

This will be ABI incompatible between GCC and Clang, that doesn't look like
a good idea to me.  I thought the plan is to use what you have in the
_GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION case always, except that if
__builtin_source_location isn't available, initialize _M_data to nullptr.

	Jakub
JeanHeyd Meneide Dec. 28, 2019, 3:27 a.m. UTC | #2
On Fri, Dec 27, 2019 at 2:33 PM Jakub Jelinek <jakub@redhat.com> wrote:
>
> This will be ABI incompatible between GCC and Clang, that doesn't look like
> a good idea to me.  I thought the plan is to use what you have in the
> _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION case always, except that if
> __builtin_source_location isn't available, initialize _M_data to nullptr.

You're right, it's probably bad to have an implementation that
switches. I guess that means clang folks will have to implement the
builtin too at some point (but Jonathan's comment in the
__builtin_source_location patch said they might not, so I'm not sure
what to do for Clang here I guess?).

To more clearly explain the test failures and the static_assert
failures, there are cases where -- when the default argument can be
manifestly constant evaluated -- it does not report the a function
name or anything at all. It also uses the line of where the Nonstatic
Data Member Initializer is for initialization of class members, rather
than the line of the constructor where the initialization happens.
These are things that the Standard's examples say *should* work, but I
don't know how normative Examples are in the standard that use
comments to explain things:
http://eel.is/c++draft/support.srcloc#cons-4

Best Wishes,
JeanHeyd
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 6300de9e96d..fc593c7c461 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -70,6 +70,7 @@ std_headers = \
 	${std_srcdir}/scoped_allocator \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
+	${std_srcdir}/source_location \
 	${std_srcdir}/span \
 	${std_srcdir}/sstream \
 	${std_srcdir}/stack \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index ae4a493ea65..c104ffb28ab 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -414,6 +414,7 @@ std_headers = \
 	${std_srcdir}/scoped_allocator \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
+	${std_srcdir}/source_location \
 	${std_srcdir}/span \
 	${std_srcdir}/sstream \
 	${std_srcdir}/stack \
diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
index 7ccfc5f199d..2d2ec96a925 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -630,6 +630,7 @@ namespace std
 
 #if __GNUC__ >= 7
 // Assume these are available if the compiler claims to be a recent GCC:
+# define _GLIBCXX_HAVE_BUILTIN_LINE 1
 # define _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP 1
 # define _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE 1
 # define _GLIBCXX_HAVE_BUILTIN_LAUNDER 1
@@ -637,6 +638,9 @@ namespace std
 # if __GNUC__ >= 9
 #  define _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED 1
 # endif
+# if __GNUC__ >= 10
+#  define _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION 1
+# endif
 #elif defined(__is_identifier) && defined(__has_builtin)
 // For non-GNU compilers:
 # if ! __is_identifier(__has_unique_object_representations)
@@ -654,6 +658,15 @@ namespace std
 # if ! __is_identifier(__is_same)
 #  define _GLIBCXX_BUILTIN_IS_SAME_AS(T, U) __is_same(T, U)
 # endif
+# if __has_builtin(__builtin_source_location)
+#  define _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION 1
+# endif
+# if __has_builtin(__builtin_LINE)
+#  define _GLIBCXX_HAVE_BUILTIN_LINE 1
+# endif
+# if __has_builtin(__builtin_COLUMN)
+#  define _GLIBCXX_HAVE_BUILTIN_COLUMN 1
+# endif
 #endif // GCC
 
 // PSTL configuration
diff --git a/libstdc++-v3/include/std/source_location b/libstdc++-v3/include/std/source_location
new file mode 100644
index 00000000000..e2727ebd196
--- /dev/null
+++ b/libstdc++-v3/include/std/source_location
@@ -0,0 +1,103 @@
+// Component for retrieving function, line and column source info. -*- 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 source_location
+ *  This is a Standard C++ Library header.
+ */
+
+//
+// P1208 source_location library
+// Contributed by ThePhD with <3
+//
+
+#ifndef _GLIBCXX_SOURCE_LOCATION
+#define _GLIBCXX_SOURCE_LOCATION 1
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+
+#include <bits/c++config.h>
+#include <cstdint>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#define __cpp_lib_source_location 201907L
+
+  struct source_location
+  {
+  private:
+    struct __impl
+    {
+      const char *_M_file_name;
+      const char *_M_function_name;
+      unsigned int _M_line, _M_column;
+    };
+
+  public:
+    static consteval source_location
+    current (const void *__src_loc_impl =
+#ifdef _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION
+	       __builtin_source_location ()
+#else
+	       nullptr
+#endif
+    ) noexcept
+    {
+      source_location __ret;
+      __ret._M_data = static_cast<const __impl *>(__src_loc_impl);
+      return __ret;
+    }
+
+    constexpr
+    source_location () noexcept
+    : _M_data ()
+    { }
+
+    constexpr const char *
+    file_name () const noexcept
+    { return _M_data ? _M_data->_M_file_name : ""; }
+
+    constexpr const char *
+    function_name () const noexcept
+    { return _M_data ? _M_data->_M_function_name : ""; }
+
+    constexpr uint_least32_t
+    line () const noexcept
+    { return _M_data ? _M_data->_M_line : 0; }
+  
+    constexpr uint_least32_t
+    column () const noexcept
+    { return _M_data ? _M_data->_M_column : 0; }
+
+  private:
+    const __impl *_M_data;
+  };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+#endif // _GLIBCXX_SOURCE_LOCATION
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index e55a092eb89..4357d7de71c 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -196,6 +196,11 @@
 #endif
 #define __cpp_lib_to_array 201907L
 #endif
+#if defined(_GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION)
+# define __cpp_lib_is_constant_evaluated 201907L
+#elif defined(_GLIBCXX_HAVE_BUILTIN_LINE) && defined(_GLIBCXX_HAVE_BUILTIN_COLUMN)
+# define __cpp_lib_is_constant_evaluated 201907L
+#endif
 #endif // C++2a
 #endif // C++17
 #endif // C++14
diff --git a/libstdc++-v3/testsuite/std/support/srcloc/consteval.std.n4842.C b/libstdc++-v3/testsuite/std/support/srcloc/consteval.std.n4842.C
new file mode 100644
index 00000000000..7ae135394d5
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/support/srcloc/consteval.std.n4842.C
@@ -0,0 +1,142 @@
+// 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/>.
+
+// Example from C++ Standard Working Draft N4842, November 2019 Mailing
+// Adapted for testing.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <source_location>
+#include <string_view>
+
+struct s {
+  std::source_location member = std::source_location::current();
+  int other_member = 1;
+  
+  constexpr s(std::source_location loc = std::source_location::current())
+    : member(loc) // values of member refer to calling function
+  { }
+
+  constexpr s(int blather) : // values of member refer to this location
+    other_member(blather)
+  { }
+};
+
+constexpr std::source_location
+f(std::source_location a = std::source_location::current())
+{ return a; }
+
+constexpr std::source_location
+g()
+{
+  std::source_location c = std::source_location::current();
+  return f(c);
+}
+
+#include "std.n4842.h"
+
+int main ()
+{
+  constexpr std::source_location main_sl = std::source_location::current();
+  constexpr std::source_location f_arg_sl = f(main_sl);
+  constexpr std::source_location g_sl = g();
+  constexpr std::source_location f_sl = f();
+  constexpr std::source_location h_sl = h();
+  constexpr s member_main_sl(main_sl);
+  constexpr s member_defaulted_sl(1);
+  constexpr s member_sl = s{};
+
+  using namespace std::string_view_literals;
+
+
+  static_assert (std::source_location::current ().line () == __LINE__);
+  static_assert (std::source_location::current ().column () == 49);
+
+
+  constexpr std::string_view main_sl_fn_name(main_sl.function_name());
+  constexpr std::string_view main_sl_fi_name(main_sl.file_name());
+  static_assert(main_sl.line() == 55);
+  // closing paren of call
+  static_assert(main_sl.column() == 74);
+  static_assert(main_sl_fn_name.ends_with("main"sv));
+  static_assert(main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view f_arg_sl_fn_name(f_arg_sl.function_name());
+  constexpr std::string_view f_arg_sl_fi_name(f_arg_sl.file_name());
+  static_assert(f_arg_sl.line() == 55);
+  // closing paren of call
+  static_assert(f_arg_sl.column() == 74);
+  static_assert(f_arg_sl_fn_name.ends_with("main"sv));
+  static_assert(f_arg_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view g_sl_fn_name(g_sl.function_name());
+  constexpr std::string_view g_sl_fi_name(g_sl.file_name());
+  static_assert(g_sl.line() == 47);
+  static_assert(g_sl.column() == 58); // closing paren of call
+  static_assert(g_sl_fn_name.ends_with("g"sv));
+  static_assert(g_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view h_sl_fn_name(h_sl.function_name());
+  constexpr std::string_view h_sl_fi_name(h_sl.file_name());
+  static_assert(h_sl.line() == 23);
+  static_assert(h_sl.column() == 58); // closing paren of call
+  static_assert(h_sl_fn_name.ends_with("h"sv));
+  static_assert(h_sl_fi_name.ends_with("std.n4842.h"sv));
+
+  constexpr std::string_view member_main_sl_fn_name(member_main_sl.member.function_name());
+  constexpr std::string_view member_main_sl_fi_name(member_main_sl.member.file_name());
+  static_assert(member_main_sl.member.line() == 55);
+  static_assert(member_main_sl.member.column() == 74);
+  static_assert(member_main_sl_fn_name.ends_with("main"sv));
+  static_assert(member_main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  // FIXME: Jakub's patch does not
+  // properly get the name of the calling function
+  // when used as a default argument,
+  // nor does it follow the example in the std
+  // FIXME: All 3 cases below are busted
+  constexpr std::string_view member_defaulted_sl_fn_name(
+    member_defaulted_sl.member.function_name());
+  constexpr std::string_view member_defaulted_sl_fi_name(
+    member_defaulted_sl.member.file_name());
+  static_assert(member_defaulted_sl.member.line() == 35);
+  // closing paren of constructor declaration
+  static_assert(member_defaulted_sl.member.column() == 26);
+  static_assert(member_defaulted_sl_fn_name.ends_with("s::s"sv));
+  static_assert(member_defaulted_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view member_sl_fn_name(
+    member_sl.member.function_name());
+  constexpr std::string_view member_sl_fi_name(
+    member_sl.member.file_name());
+  static_assert(member_sl.member.line() == 62);
+  // closing brace/paren of constructor
+  static_assert(member_sl.member.column() == 29);
+  static_assert(member_sl_fn_name.ends_with("main"sv));
+  static_assert(member_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view f_sl_fn_name(f_sl.function_name());
+  constexpr std::string_view f_sl_fi_name(f_sl.file_name());
+  static_assert(f_sl.line() == 58);
+  // closing paren of call
+  static_assert(f_sl.column() == 43);
+  static_assert(f_sl_fn_name.ends_with("main"sv));
+  static_assert(f_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.C b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.C
new file mode 100644
index 00000000000..78b6da0c88e
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.C
@@ -0,0 +1,139 @@
+// 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/>.
+
+// Example from C++ Standard Working Draft N4842, November 2019 Mailing
+// Adapted for testing.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <source_location>
+#include <string_view>
+#include <testsuite_hooks.h>
+#include "std.n4842.h"
+
+struct s {
+  std::source_location member = std::source_location::current();
+  int other_member = 1;
+  
+  s(std::source_location loc = std::source_location::current())
+    : member(loc) // values of member refer to calling function
+  { }
+
+  s(int blather) : // values of member refer to this location
+    other_member(blather)
+  { }
+};
+
+std::source_location
+f(std::source_location a = std::source_location::current());
+
+std::source_location
+f(std::source_location a)
+{ return a; }
+
+std::source_location
+g()
+{
+  std::source_location c = std::source_location::current();
+  return f(c);
+}
+#include <iostream>
+int main ()
+{
+  std::source_location main_sl = std::source_location::current();
+  std::source_location f_arg_sl = f(main_sl);
+  std::source_location g_sl = g();
+  std::source_location f_sl = f();
+  std::source_location h_sl = h();
+  s member_main_sl(main_sl);
+  s member_defaulted_sl(1);
+  s member_sl = s{};
+
+  using namespace std::string_view_literals;
+
+  std::string_view main_sl_fn_name(main_sl.function_name());
+  std::string_view main_sl_fi_name(main_sl.file_name());
+  VERIFY(main_sl.line() == 58);
+  // closing paren of call
+  VERIFY(main_sl.column() == 64);
+  VERIFY(main_sl_fn_name.ends_with("main"sv));
+  VERIFY(main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view f_arg_sl_fn_name(f_arg_sl.function_name());
+  std::string_view f_arg_sl_fi_name(f_arg_sl.file_name());
+  VERIFY(f_arg_sl.line() == 58);
+  // closing paren of call
+  VERIFY(f_arg_sl.column() == 64);
+  VERIFY(f_arg_sl_fn_name.ends_with("main"sv));
+  VERIFY(f_arg_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view g_sl_fn_name(g_sl.function_name());
+  std::string_view g_sl_fi_name(g_sl.file_name());
+  VERIFY(g_sl.line() == 52);
+  VERIFY(g_sl.column() == 58); // closing paren of call
+  VERIFY(g_sl_fn_name.ends_with("g"sv));
+  VERIFY(g_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view h_sl_fn_name(h_sl.function_name());
+  std::string_view h_sl_fi_name(h_sl.file_name());
+  VERIFY(h_sl.line() == 23);
+  VERIFY(h_sl.column() == 58); // closing paren of call
+  VERIFY(h_sl_fn_name.ends_with("h"sv));
+  VERIFY(h_sl_fi_name.ends_with("std.n4842.h"sv));
+
+  std::string_view member_main_sl_fn_name(member_main_sl.member.function_name());
+  std::string_view member_main_sl_fi_name(member_main_sl.member.file_name());
+  VERIFY(member_main_sl.member.line() == 58);
+  VERIFY(member_main_sl.member.column() == 64);
+  VERIFY(member_main_sl_fn_name.ends_with("main"sv));
+  VERIFY(member_main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view member_defaulted_sl_fn_name(
+    member_defaulted_sl.member.function_name());
+  std::string_view member_defaulted_sl_fi_name(
+    member_defaulted_sl.member.file_name());
+  std::cout << member_defaulted_sl.member.line() << std::endl;
+  std::cout << member_defaulted_sl.member.column() << std::endl;
+  std::cout << member_defaulted_sl_fn_name << std::endl;
+  std::cout << member_defaulted_sl_fi_name << std::endl;
+  VERIFY(member_defaulted_sl.member.line() == 37);
+  // closing paren of constructor declaration
+  VERIFY(member_defaulted_sl.member.column() == 26);
+  VERIFY(member_defaulted_sl_fn_name.ends_with("s::s"sv));
+  VERIFY(member_defaulted_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view member_sl_fn_name(
+    member_sl.member.function_name());
+  std::string_view member_sl_fi_name(
+    member_sl.member.file_name());
+  VERIFY(member_sl.member.line() == 62);
+  // closing brace/paren of constructor
+  VERIFY(member_sl.member.column() == 29);
+  VERIFY(member_sl_fn_name.ends_with("main"sv));
+  VERIFY(member_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view f_sl_fn_name(f_sl.function_name());
+  std::string_view f_sl_fi_name(f_sl.file_name());
+  VERIFY(f_sl.line() == 58);
+  // closing paren of call
+  VERIFY(f_sl.column() == 43);
+  VERIFY(f_sl_fn_name.ends_with("main"sv));
+  VERIFY(f_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.h b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.h
new file mode 100644
index 00000000000..50ff5c41bea
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.h
@@ -0,0 +1,25 @@
+// 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/>.
+
+#include <source_location>
+
+constexpr std::source_location
+h ()
+{
+  std::source_location a = std::source_location::current();
+  return a;
+}
Jonathan Wakely Jan. 2, 2020, 10:28 a.m. UTC | #3
On 27/12/19 22:27 -0500, JeanHeyd Meneide wrote:
>On Fri, Dec 27, 2019 at 2:33 PM Jakub Jelinek <jakub@redhat.com> wrote:
>>
>> This will be ABI incompatible between GCC and Clang, that doesn't look like
>> a good idea to me.  I thought the plan is to use what you have in the
>> _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION case always, except that if
>> __builtin_source_location isn't available, initialize _M_data to nullptr.
>
>You're right, it's probably bad to have an implementation that
>switches. I guess that means clang folks will have to implement the
>builtin too at some point (but Jonathan's comment in the
>__builtin_source_location patch said they might not, so I'm not sure
>what to do for Clang here I guess?).

Do nothing - compiling with Clang won't define std::source_location at
all.
JeanHeyd Meneide Jan. 2, 2020, 9:57 p.m. UTC | #4
On Thu, Jan 2, 2020 at 5:28 AM Jonathan Wakely <jwakely@redhat.com> wrote:
>
> Do nothing - compiling with Clang won't define std::source_location at
> all.

You got it! Patch re-done after discussion here
(https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93093) and recommended
no-Clang change.

2020-01-02  JeanHeyd "ThePhD" Meneide  <phdofthehouse@gmail.com>

        * include/Makefile.in: add source_location header
        * include/bits/c++config: Add new detection macros for
          LINE, COLUMN, and SOURCE_LOCATION builtins.
        * include/std/source_location: New.
        * testuite/std/support/srcloc/consteval.std.n4842.h (new):
test source_location
        * testuite/std/support/srcloc/std.n4842.C (new): test source_location
        * testuite/std/support/srcloc/std.n4842.h (new): test source_location
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index ae4a493ea65..c104ffb28ab 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -414,6 +414,7 @@ std_headers = \
 	${std_srcdir}/scoped_allocator \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
+	${std_srcdir}/source_location \
 	${std_srcdir}/span \
 	${std_srcdir}/sstream \
 	${std_srcdir}/stack \
diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
index f983743b052..6ca431b24ee 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -630,6 +630,7 @@ namespace std
 
 #if __GNUC__ >= 7
 // Assume these are available if the compiler claims to be a recent GCC:
+# define _GLIBCXX_HAVE_BUILTIN_LINE 1
 # define _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP 1
 # define _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE 1
 # define _GLIBCXX_HAVE_BUILTIN_LAUNDER 1
@@ -637,6 +638,9 @@ namespace std
 # if __GNUC__ >= 9
 #  define _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED 1
 # endif
+# if __GNUC__ >= 10
+#  define _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION 1
+# endif
 #elif defined(__is_identifier) && defined(__has_builtin)
 // For non-GNU compilers:
 # if ! __is_identifier(__has_unique_object_representations)
@@ -654,6 +658,15 @@ namespace std
 # if ! __is_identifier(__is_same)
 #  define _GLIBCXX_BUILTIN_IS_SAME_AS(T, U) __is_same(T, U)
 # endif
+# if __has_builtin(__builtin_source_location)
+#  define _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION 1
+# endif
+# if __has_builtin(__builtin_LINE)
+#  define _GLIBCXX_HAVE_BUILTIN_LINE 1
+# endif
+# if __has_builtin(__builtin_COLUMN)
+#  define _GLIBCXX_HAVE_BUILTIN_COLUMN 1
+# endif
 #endif // GCC
 
 // PSTL configuration
diff --git a/libstdc++-v3/include/std/source_location b/libstdc++-v3/include/std/source_location
new file mode 100644
index 00000000000..4c805df0dfa
--- /dev/null
+++ b/libstdc++-v3/include/std/source_location
@@ -0,0 +1,101 @@
+// Component for retrieving function, line and column source info. -*- C++ -*-
+
+// Copyright (C) 2019-2020 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 source_location
+ *  This is a Standard C++ Library header.
+ */
+
+//
+// P1208 source_location library
+// Contributed by ThePhD with <3
+//
+
+#ifndef _GLIBCXX_SOURCE_LOCATION
+#define _GLIBCXX_SOURCE_LOCATION 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <cstdint>
+
+#if __cplusplus > 201703L
+#ifdef _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#define __cpp_lib_source_location 201907L
+
+  struct source_location
+  {
+  private:
+    struct __impl
+    {
+      const char *_M_file_name;
+      const char *_M_function_name;
+      unsigned int _M_line, _M_column;
+    };
+
+  public:
+    static consteval source_location
+    current (const void *__src_loc_impl = __builtin_source_location ()) noexcept
+    {
+      source_location __ret;
+      __ret._M_data = static_cast<const __impl *>(__src_loc_impl);
+      return __ret;
+    }
+
+    constexpr
+    source_location () noexcept
+    : _M_data ()
+    { }
+
+    constexpr const char *
+    file_name () const noexcept
+    { return _M_data ? _M_data->_M_file_name : ""; }
+
+    constexpr const char *
+    function_name () const noexcept
+    { return _M_data ? _M_data->_M_function_name : ""; }
+
+    constexpr uint_least32_t
+    line () const noexcept
+    { return _M_data ? _M_data->_M_line : 0; }
+  
+    constexpr uint_least32_t
+    column () const noexcept
+    { return _M_data ? _M_data->_M_column : 0; }
+
+  private:
+    const __impl *_M_data;
+  };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // has __builtin_source_location
+#endif // C++20
+
+#endif // _GLIBCXX_SOURCE_LOCATION
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index ab8111468e4..e482c87ac36 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -196,6 +196,11 @@
 #endif
 #define __cpp_lib_to_array 201907L
 #endif
+#if defined(_GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION)
+# define __cpp_lib_source_location 201907L
+#elif defined(_GLIBCXX_HAVE_BUILTIN_LINE) && defined(_GLIBCXX_HAVE_BUILTIN_COLUMN)
+# define __cpp_lib_is_constant_evaluated 201907L
+#endif
 #endif // C++2a
 #endif // C++17
 #endif // C++14
diff --git a/libstdc++-v3/testsuite/std/support/srcloc/consteval.std.n4842.C b/libstdc++-v3/testsuite/std/support/srcloc/consteval.std.n4842.C
new file mode 100644
index 00000000000..7c057b60e48
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/support/srcloc/consteval.std.n4842.C
@@ -0,0 +1,147 @@
+// Copyright (C) 2019-2020 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/>.
+
+// Example from C++ Standard Working Draft N4842, November 2019 Mailing
+// Adapted for testing.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <source_location>
+#include <string_view>
+
+struct s {
+  std::source_location member = std::source_location::current();
+  int other_member = 1;
+  
+  constexpr s(std::source_location loc = std::source_location::current())
+    : member(loc) // values of member refer to calling function
+  { }
+
+  constexpr s(int blather) : // values of member refer to this location
+    other_member(blather)
+  { }
+};
+
+constexpr std::source_location
+f(std::source_location a = std::source_location::current())
+{ return a; }
+
+constexpr std::source_location
+g()
+{
+  std::source_location c = std::source_location::current();
+  return f(c);
+}
+
+#include "std.n4842.h"
+
+int main ()
+{
+  constexpr std::source_location main_sl = std::source_location::current();
+  constexpr std::source_location f_arg_sl = f(main_sl);
+  constexpr std::source_location g_sl = g();
+  constexpr std::source_location f_sl = f();
+  constexpr std::source_location h_sl = h();
+  constexpr s member_main_sl(main_sl);
+  constexpr s member_defaulted_sl(1);
+  constexpr s member_sl = s{};
+
+  using namespace std::string_view_literals;
+
+
+  static_assert (std::source_location::current ().line () == __LINE__);
+  static_assert (std::source_location::current ().column () == 49);
+
+
+  constexpr std::string_view main_sl_fn_name(main_sl.function_name());
+  constexpr std::string_view main_sl_fi_name(main_sl.file_name());
+  static_assert(main_sl.line() == 55);
+  // closing paren of call
+  static_assert(main_sl.column() == 74);
+  static_assert(main_sl_fn_name.ends_with("main"sv));
+  static_assert(main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view f_arg_sl_fn_name(f_arg_sl.function_name());
+  constexpr std::string_view f_arg_sl_fi_name(f_arg_sl.file_name());
+  static_assert(f_arg_sl.line() == 55);
+  // closing paren of call
+  static_assert(f_arg_sl.column() == 74);
+  static_assert(f_arg_sl_fn_name.ends_with("main"sv));
+  static_assert(f_arg_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view g_sl_fn_name(g_sl.function_name());
+  constexpr std::string_view g_sl_fi_name(g_sl.file_name());
+  static_assert(g_sl.line() == 47);
+  static_assert(g_sl.column() == 58); // closing paren of call
+  static_assert(g_sl_fn_name.ends_with("g"sv));
+  static_assert(g_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view h_sl_fn_name(h_sl.function_name());
+  constexpr std::string_view h_sl_fi_name(h_sl.file_name());
+  static_assert(h_sl.line() == 23);
+  static_assert(h_sl.column() == 58); // closing paren of call
+  static_assert(h_sl_fn_name.ends_with("h"sv));
+  static_assert(h_sl_fi_name.ends_with("std.n4842.h"sv));
+
+  constexpr std::string_view member_main_sl_fn_name(member_main_sl.member.function_name());
+  constexpr std::string_view member_main_sl_fi_name(member_main_sl.member.file_name());
+  static_assert(member_main_sl.member.line() == 55);
+  static_assert(member_main_sl.member.column() == 74);
+  static_assert(member_main_sl_fn_name.ends_with("main"sv));
+  static_assert(member_main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  // FIXME: All 3 cases below are busted
+  // Which is user-hostile, but right now
+  // constant evaluation evaluates the call immediately
+  // and without call stack information...
+  constexpr std::string_view member_defaulted_sl_fi_name(
+    member_defaulted_sl.member.file_name());
+#if 0
+  constexpr std::string_view member_defaulted_sl_fn_name(
+    member_defaulted_sl.member.function_name());
+  static_assert(member_defaulted_sl.member.line() == 35);
+  // closing paren of constructor declaration
+  static_assert(member_defaulted_sl.member.column() == 26);
+  static_assert(member_defaulted_sl_fn_name.ends_with("s::s"sv));
+#endif
+  static_assert(member_defaulted_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view member_sl_fi_name(
+    member_sl.member.file_name());
+#if 0
+  constexpr std::string_view member_sl_fn_name(
+    member_sl.member.function_name());
+  static_assert(member_sl.member.line() == 62);
+  // closing brace/paren of constructor
+  static_assert(member_sl.member.column() == 29);
+  static_assert(member_sl_fn_name.ends_with("main"sv));
+#endif
+  static_assert(member_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view f_sl_fi_name(f_sl.file_name());
+#if 0
+  constexpr std::string_view f_sl_fn_name(f_sl.function_name());
+  static_assert(f_sl.line() == 58);
+  // closing paren of call
+  static_assert(f_sl.column() == 43);
+  static_assert(f_sl_fn_name.ends_with("main"sv));
+#endif
+  static_assert(f_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.C b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.C
new file mode 100644
index 00000000000..fecd79d139a
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.C
@@ -0,0 +1,149 @@
+// Copyright (C) 2019-2020 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/>.
+
+// Example from C++ Standard Working Draft N4842, November 2019 Mailing
+// Adapted for testing.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <source_location>
+#include <string_view>
+#include <testsuite_hooks.h>
+#include "std.n4842.h"
+
+struct s {
+  std::source_location member = std::source_location::current();
+  int other_member = 1;
+  
+  s(std::source_location loc = std::source_location::current())
+    : member(loc) // values of member refer to calling function
+  { }
+
+  s(int blather) : // values of member refer to this location
+    other_member(blather)
+  { }
+};
+
+std::source_location
+f(std::source_location a = std::source_location::current());
+
+std::source_location
+f(std::source_location a)
+{ return a; }
+
+std::source_location
+g()
+{
+  std::source_location c = std::source_location::current();
+  return f(c);
+}
+
+int main ()
+{
+  std::source_location main_sl = std::source_location::current();
+  std::source_location f_arg_sl = f(main_sl);
+  std::source_location g_sl = g();
+  std::source_location f_sl = f();
+  std::source_location h_sl = h();
+  s member_main_sl(main_sl);
+  s member_defaulted_sl(1);
+  s member_sl = s{};
+
+  using namespace std::string_view_literals;
+
+  std::string_view main_sl_fn_name(main_sl.function_name());
+  std::string_view main_sl_fi_name(main_sl.file_name());
+  VERIFY(main_sl.line() == 58);
+  // closing paren of call
+  VERIFY(main_sl.column() == 64);
+  VERIFY(main_sl_fn_name.ends_with("main"sv));
+  VERIFY(main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view f_arg_sl_fn_name(f_arg_sl.function_name());
+  std::string_view f_arg_sl_fi_name(f_arg_sl.file_name());
+  VERIFY(f_arg_sl.line() == 58);
+  // closing paren of call
+  VERIFY(f_arg_sl.column() == 64);
+  VERIFY(f_arg_sl_fn_name.ends_with("main"sv));
+  VERIFY(f_arg_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view g_sl_fn_name(g_sl.function_name());
+  std::string_view g_sl_fi_name(g_sl.file_name());
+  VERIFY(g_sl.line() == 52);
+  VERIFY(g_sl.column() == 58); // closing paren of call
+  VERIFY(g_sl_fn_name.ends_with("g"sv));
+  VERIFY(g_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view h_sl_fn_name(h_sl.function_name());
+  std::string_view h_sl_fi_name(h_sl.file_name());
+  VERIFY(h_sl.line() == 23);
+  VERIFY(h_sl.column() == 58); // closing paren of call
+  VERIFY(h_sl_fn_name.ends_with("h"sv));
+  VERIFY(h_sl_fi_name.ends_with("std.n4842.h"sv));
+
+  std::string_view member_main_sl_fn_name(member_main_sl.member.function_name());
+  std::string_view member_main_sl_fi_name(member_main_sl.member.file_name());
+  VERIFY(member_main_sl.member.line() == 58);
+  VERIFY(member_main_sl.member.column() == 64);
+  VERIFY(member_main_sl_fn_name.ends_with("main"sv));
+  VERIFY(member_main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  // FIXME: the following cases are all busted
+  // despite the standard giving examples to the contrary.
+  // Unfortunately GCC's constant folder / evaluator
+  // (and the standard's) manifestly constant evaluates
+  // default arguments, and at that point GCC has no
+  // call stack information for anyone to
+  // produce additional information.
+  // It will require extra work to make these work with it.
+  std::string_view member_defaulted_sl_fi_name(
+    member_defaulted_sl.member.file_name());
+#if 0
+  std::string_view member_defaulted_sl_fn_name(
+    member_defaulted_sl.member.function_name());
+  VERIFY(member_defaulted_sl.member.line() == 37);
+  // closing paren of constructor declaration
+  VERIFY(member_defaulted_sl.member.column() == 26);
+  VERIFY(member_defaulted_sl_fn_name.ends_with("s::s"sv));
+#endif
+  VERIFY(member_defaulted_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view member_sl_fi_name(
+    member_sl.member.file_name());
+#if 0
+  std::string_view member_sl_fn_name(
+    member_sl.member.function_name());
+  VERIFY(member_sl.member.line() == 62);
+  // closing brace/paren of constructor
+  VERIFY(member_sl.member.column() == 29);
+  VERIFY(member_sl_fn_name.ends_with("main"sv));
+#endif
+  VERIFY(member_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view f_sl_fi_name(f_sl.file_name());
+#if 0
+  std::string_view f_sl_fn_name(f_sl.function_name());
+  VERIFY(f_sl.line() == 58);
+  // closing paren of call
+  VERIFY(f_sl.column() == 43);
+  VERIFY(f_sl_fn_name.ends_with("main"sv));
+#endif
+  VERIFY(f_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.h b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.h
new file mode 100644
index 00000000000..50ff5c41bea
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.h
@@ -0,0 +1,25 @@
+// 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/>.
+
+#include <source_location>
+
+constexpr std::source_location
+h ()
+{
+  std::source_location a = std::source_location::current();
+  return a;
+}
Jakub Jelinek Jan. 2, 2020, 10:07 p.m. UTC | #5
On Thu, Jan 02, 2020 at 04:57:01PM -0500, JeanHeyd Meneide wrote:
> +#if defined(_GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION)
> +# define __cpp_lib_source_location 201907L
> +#elif defined(_GLIBCXX_HAVE_BUILTIN_LINE) && defined(_GLIBCXX_HAVE_BUILTIN_COLUMN)
> +# define __cpp_lib_is_constant_evaluated 201907L

How is __cpp_lib_is_constant_evaluated related to presence of __builtin_LINE
and __builtin_COLUMN?  I believe you don't want the #elif and following
line at all, and then you don't need everything related to
_GLIBCXX_HAVE_BUILTIN_{LINE,COLUMN} either.

	Jakub
JeanHeyd Meneide Jan. 2, 2020, 10:20 p.m. UTC | #6
On Thu, Jan 2, 2020 at 5:07 PM Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Thu, Jan 02, 2020 at 04:57:01PM -0500, JeanHeyd Meneide wrote:
> > +#if defined(_GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION)
> > +# define __cpp_lib_source_location 201907L
> > +#elif defined(_GLIBCXX_HAVE_BUILTIN_LINE) && defined(_GLIBCXX_HAVE_BUILTIN_COLUMN)
> > +# define __cpp_lib_is_constant_evaluated 201907L
>
> How is __cpp_lib_is_constant_evaluated related to presence of __builtin_LINE
> and __builtin_COLUMN?

Oops. Sorry; fat-fingered the diff a little!
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index ae4a493ea65..c104ffb28ab 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -414,6 +414,7 @@ std_headers = \
 	${std_srcdir}/scoped_allocator \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
+	${std_srcdir}/source_location \
 	${std_srcdir}/span \
 	${std_srcdir}/sstream \
 	${std_srcdir}/stack \
diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
index f983743b052..6ca431b24ee 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -630,6 +630,7 @@ namespace std
 
 #if __GNUC__ >= 7
 // Assume these are available if the compiler claims to be a recent GCC:
 # define _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP 1
 # define _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE 1
 # define _GLIBCXX_HAVE_BUILTIN_LAUNDER 1
@@ -637,6 +638,9 @@ namespace std
 # if __GNUC__ >= 9
 #  define _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED 1
 # endif
+# if __GNUC__ >= 10
+#  define _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION 1
+# endif
 #elif defined(__is_identifier) && defined(__has_builtin)
 // For non-GNU compilers:
 # if ! __is_identifier(__has_unique_object_representations)
@@ -654,6 +658,15 @@ namespace std
 # if ! __is_identifier(__is_same)
 #  define _GLIBCXX_BUILTIN_IS_SAME_AS(T, U) __is_same(T, U)
 # endif
+# if __has_builtin(__builtin_source_location)
+#  define _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION 1
+# endif
 #endif // GCC
 
 // PSTL configuration
diff --git a/libstdc++-v3/include/std/source_location b/libstdc++-v3/include/std/source_location
new file mode 100644
index 00000000000..4c805df0dfa
--- /dev/null
+++ b/libstdc++-v3/include/std/source_location
@@ -0,0 +1,101 @@
+// Component for retrieving function, line and column source info. -*- C++ -*-
+
+// Copyright (C) 2019-2020 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 source_location
+ *  This is a Standard C++ Library header.
+ */
+
+//
+// P1208 source_location library
+// Contributed by ThePhD with <3
+//
+
+#ifndef _GLIBCXX_SOURCE_LOCATION
+#define _GLIBCXX_SOURCE_LOCATION 1
+
+#pragma GCC system_header
+
+#include <bits/c++config.h>
+#include <cstdint>
+
+#if __cplusplus > 201703L
+#ifdef _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#define __cpp_lib_source_location 201907L
+
+  struct source_location
+  {
+  private:
+    struct __impl
+    {
+      const char *_M_file_name;
+      const char *_M_function_name;
+      unsigned int _M_line, _M_column;
+    };
+
+  public:
+    static consteval source_location
+    current (const void *__src_loc_impl = __builtin_source_location ()) noexcept
+    {
+      source_location __ret;
+      __ret._M_data = static_cast<const __impl *>(__src_loc_impl);
+      return __ret;
+    }
+
+    constexpr
+    source_location () noexcept
+    : _M_data ()
+    { }
+
+    constexpr const char *
+    file_name () const noexcept
+    { return _M_data ? _M_data->_M_file_name : ""; }
+
+    constexpr const char *
+    function_name () const noexcept
+    { return _M_data ? _M_data->_M_function_name : ""; }
+
+    constexpr uint_least32_t
+    line () const noexcept
+    { return _M_data ? _M_data->_M_line : 0; }
+  
+    constexpr uint_least32_t
+    column () const noexcept
+    { return _M_data ? _M_data->_M_column : 0; }
+
+  private:
+    const __impl *_M_data;
+  };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // has __builtin_source_location
+#endif // C++20
+
+#endif // _GLIBCXX_SOURCE_LOCATION
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index ab8111468e4..e482c87ac36 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -196,6 +196,11 @@
 #endif
 #define __cpp_lib_to_array 201907L
 #endif
+#if defined(_GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION)
+# define __cpp_lib_source_location 201907L
+#endif
 #endif // C++2a
 #endif // C++17
 #endif // C++14
diff --git a/libstdc++-v3/testsuite/std/support/srcloc/consteval.std.n4842.C b/libstdc++-v3/testsuite/std/support/srcloc/consteval.std.n4842.C
new file mode 100644
index 00000000000..7c057b60e48
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/support/srcloc/consteval.std.n4842.C
@@ -0,0 +1,147 @@
+// Copyright (C) 2019-2020 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/>.
+
+// Example from C++ Standard Working Draft N4842, November 2019 Mailing
+// Adapted for testing.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <source_location>
+#include <string_view>
+
+struct s {
+  std::source_location member = std::source_location::current();
+  int other_member = 1;
+  
+  constexpr s(std::source_location loc = std::source_location::current())
+    : member(loc) // values of member refer to calling function
+  { }
+
+  constexpr s(int blather) : // values of member refer to this location
+    other_member(blather)
+  { }
+};
+
+constexpr std::source_location
+f(std::source_location a = std::source_location::current())
+{ return a; }
+
+constexpr std::source_location
+g()
+{
+  std::source_location c = std::source_location::current();
+  return f(c);
+}
+
+#include "std.n4842.h"
+
+int main ()
+{
+  constexpr std::source_location main_sl = std::source_location::current();
+  constexpr std::source_location f_arg_sl = f(main_sl);
+  constexpr std::source_location g_sl = g();
+  constexpr std::source_location f_sl = f();
+  constexpr std::source_location h_sl = h();
+  constexpr s member_main_sl(main_sl);
+  constexpr s member_defaulted_sl(1);
+  constexpr s member_sl = s{};
+
+  using namespace std::string_view_literals;
+
+
+  static_assert (std::source_location::current ().line () == __LINE__);
+  static_assert (std::source_location::current ().column () == 49);
+
+
+  constexpr std::string_view main_sl_fn_name(main_sl.function_name());
+  constexpr std::string_view main_sl_fi_name(main_sl.file_name());
+  static_assert(main_sl.line() == 55);
+  // closing paren of call
+  static_assert(main_sl.column() == 74);
+  static_assert(main_sl_fn_name.ends_with("main"sv));
+  static_assert(main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view f_arg_sl_fn_name(f_arg_sl.function_name());
+  constexpr std::string_view f_arg_sl_fi_name(f_arg_sl.file_name());
+  static_assert(f_arg_sl.line() == 55);
+  // closing paren of call
+  static_assert(f_arg_sl.column() == 74);
+  static_assert(f_arg_sl_fn_name.ends_with("main"sv));
+  static_assert(f_arg_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view g_sl_fn_name(g_sl.function_name());
+  constexpr std::string_view g_sl_fi_name(g_sl.file_name());
+  static_assert(g_sl.line() == 47);
+  static_assert(g_sl.column() == 58); // closing paren of call
+  static_assert(g_sl_fn_name.ends_with("g"sv));
+  static_assert(g_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view h_sl_fn_name(h_sl.function_name());
+  constexpr std::string_view h_sl_fi_name(h_sl.file_name());
+  static_assert(h_sl.line() == 23);
+  static_assert(h_sl.column() == 58); // closing paren of call
+  static_assert(h_sl_fn_name.ends_with("h"sv));
+  static_assert(h_sl_fi_name.ends_with("std.n4842.h"sv));
+
+  constexpr std::string_view member_main_sl_fn_name(member_main_sl.member.function_name());
+  constexpr std::string_view member_main_sl_fi_name(member_main_sl.member.file_name());
+  static_assert(member_main_sl.member.line() == 55);
+  static_assert(member_main_sl.member.column() == 74);
+  static_assert(member_main_sl_fn_name.ends_with("main"sv));
+  static_assert(member_main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  // FIXME: All 3 cases below are busted
+  // Which is user-hostile, but right now
+  // constant evaluation evaluates the call immediately
+  // and without call stack information...
+  constexpr std::string_view member_defaulted_sl_fi_name(
+    member_defaulted_sl.member.file_name());
+#if 0
+  constexpr std::string_view member_defaulted_sl_fn_name(
+    member_defaulted_sl.member.function_name());
+  static_assert(member_defaulted_sl.member.line() == 35);
+  // closing paren of constructor declaration
+  static_assert(member_defaulted_sl.member.column() == 26);
+  static_assert(member_defaulted_sl_fn_name.ends_with("s::s"sv));
+#endif
+  static_assert(member_defaulted_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view member_sl_fi_name(
+    member_sl.member.file_name());
+#if 0
+  constexpr std::string_view member_sl_fn_name(
+    member_sl.member.function_name());
+  static_assert(member_sl.member.line() == 62);
+  // closing brace/paren of constructor
+  static_assert(member_sl.member.column() == 29);
+  static_assert(member_sl_fn_name.ends_with("main"sv));
+#endif
+  static_assert(member_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view f_sl_fi_name(f_sl.file_name());
+#if 0
+  constexpr std::string_view f_sl_fn_name(f_sl.function_name());
+  static_assert(f_sl.line() == 58);
+  // closing paren of call
+  static_assert(f_sl.column() == 43);
+  static_assert(f_sl_fn_name.ends_with("main"sv));
+#endif
+  static_assert(f_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.C b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.C
new file mode 100644
index 00000000000..fecd79d139a
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.C
@@ -0,0 +1,149 @@
+// Copyright (C) 2019-2020 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/>.
+
+// Example from C++ Standard Working Draft N4842, November 2019 Mailing
+// Adapted for testing.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <source_location>
+#include <string_view>
+#include <testsuite_hooks.h>
+#include "std.n4842.h"
+
+struct s {
+  std::source_location member = std::source_location::current();
+  int other_member = 1;
+  
+  s(std::source_location loc = std::source_location::current())
+    : member(loc) // values of member refer to calling function
+  { }
+
+  s(int blather) : // values of member refer to this location
+    other_member(blather)
+  { }
+};
+
+std::source_location
+f(std::source_location a = std::source_location::current());
+
+std::source_location
+f(std::source_location a)
+{ return a; }
+
+std::source_location
+g()
+{
+  std::source_location c = std::source_location::current();
+  return f(c);
+}
+
+int main ()
+{
+  std::source_location main_sl = std::source_location::current();
+  std::source_location f_arg_sl = f(main_sl);
+  std::source_location g_sl = g();
+  std::source_location f_sl = f();
+  std::source_location h_sl = h();
+  s member_main_sl(main_sl);
+  s member_defaulted_sl(1);
+  s member_sl = s{};
+
+  using namespace std::string_view_literals;
+
+  std::string_view main_sl_fn_name(main_sl.function_name());
+  std::string_view main_sl_fi_name(main_sl.file_name());
+  VERIFY(main_sl.line() == 58);
+  // closing paren of call
+  VERIFY(main_sl.column() == 64);
+  VERIFY(main_sl_fn_name.ends_with("main"sv));
+  VERIFY(main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view f_arg_sl_fn_name(f_arg_sl.function_name());
+  std::string_view f_arg_sl_fi_name(f_arg_sl.file_name());
+  VERIFY(f_arg_sl.line() == 58);
+  // closing paren of call
+  VERIFY(f_arg_sl.column() == 64);
+  VERIFY(f_arg_sl_fn_name.ends_with("main"sv));
+  VERIFY(f_arg_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view g_sl_fn_name(g_sl.function_name());
+  std::string_view g_sl_fi_name(g_sl.file_name());
+  VERIFY(g_sl.line() == 52);
+  VERIFY(g_sl.column() == 58); // closing paren of call
+  VERIFY(g_sl_fn_name.ends_with("g"sv));
+  VERIFY(g_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view h_sl_fn_name(h_sl.function_name());
+  std::string_view h_sl_fi_name(h_sl.file_name());
+  VERIFY(h_sl.line() == 23);
+  VERIFY(h_sl.column() == 58); // closing paren of call
+  VERIFY(h_sl_fn_name.ends_with("h"sv));
+  VERIFY(h_sl_fi_name.ends_with("std.n4842.h"sv));
+
+  std::string_view member_main_sl_fn_name(member_main_sl.member.function_name());
+  std::string_view member_main_sl_fi_name(member_main_sl.member.file_name());
+  VERIFY(member_main_sl.member.line() == 58);
+  VERIFY(member_main_sl.member.column() == 64);
+  VERIFY(member_main_sl_fn_name.ends_with("main"sv));
+  VERIFY(member_main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  // FIXME: the following cases are all busted
+  // despite the standard giving examples to the contrary.
+  // Unfortunately GCC's constant folder / evaluator
+  // (and the standard's) manifestly constant evaluates
+  // default arguments, and at that point GCC has no
+  // call stack information for anyone to
+  // produce additional information.
+  // It will require extra work to make these work with it.
+  std::string_view member_defaulted_sl_fi_name(
+    member_defaulted_sl.member.file_name());
+#if 0
+  std::string_view member_defaulted_sl_fn_name(
+    member_defaulted_sl.member.function_name());
+  VERIFY(member_defaulted_sl.member.line() == 37);
+  // closing paren of constructor declaration
+  VERIFY(member_defaulted_sl.member.column() == 26);
+  VERIFY(member_defaulted_sl_fn_name.ends_with("s::s"sv));
+#endif
+  VERIFY(member_defaulted_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view member_sl_fi_name(
+    member_sl.member.file_name());
+#if 0
+  std::string_view member_sl_fn_name(
+    member_sl.member.function_name());
+  VERIFY(member_sl.member.line() == 62);
+  // closing brace/paren of constructor
+  VERIFY(member_sl.member.column() == 29);
+  VERIFY(member_sl_fn_name.ends_with("main"sv));
+#endif
+  VERIFY(member_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  std::string_view f_sl_fi_name(f_sl.file_name());
+#if 0
+  std::string_view f_sl_fn_name(f_sl.function_name());
+  VERIFY(f_sl.line() == 58);
+  // closing paren of call
+  VERIFY(f_sl.column() == 43);
+  VERIFY(f_sl_fn_name.ends_with("main"sv));
+#endif
+  VERIFY(f_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.h b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.h
new file mode 100644
index 00000000000..50ff5c41bea
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.h
@@ -0,0 +1,25 @@
+// 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/>.
+
+#include <source_location>
+
+constexpr std::source_location
+h ()
+{
+  std::source_location a = std::source_location::current();
+  return a;
+}
Jonathan Wakely Dec. 3, 2020, 7:25 p.m. UTC | #7
On 02/01/20 17:20 -0500, JeanHeyd Meneide wrote:
>On Thu, Jan 2, 2020 at 5:07 PM Jakub Jelinek <jakub@redhat.com> wrote:
>>
>> On Thu, Jan 02, 2020 at 04:57:01PM -0500, JeanHeyd Meneide wrote:
>> > +#if defined(_GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION)
>> > +# define __cpp_lib_source_location 201907L
>> > +#elif defined(_GLIBCXX_HAVE_BUILTIN_LINE) && defined(_GLIBCXX_HAVE_BUILTIN_COLUMN)
>> > +# define __cpp_lib_is_constant_evaluated 201907L
>>
>> How is __cpp_lib_is_constant_evaluated related to presence of __builtin_LINE
>> and __builtin_COLUMN?
>
>Oops. Sorry; fat-fingered the diff a little!

I've committed a slightly reworked version of JeanHeyd's
<source_location> patch (see attached). Jakub has improved the
built-in so all the commented out tests work now. There's one more
compiler patch coming to use __PRETTY_FUNCTION__ for the function
name, so I'll tweak the new tests after than has gone in.

Tested powerpc64le-linux, committed to trunk.

Thanks, JeanHeyd!
diff mbox series

Patch

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 6300de9e96d..fc593c7c461 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -70,6 +70,7 @@  std_headers = \
 	${std_srcdir}/scoped_allocator \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
+	${std_srcdir}/source_location \
 	${std_srcdir}/span \
 	${std_srcdir}/sstream \
 	${std_srcdir}/stack \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index ae4a493ea65..c104ffb28ab 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -414,6 +414,7 @@  std_headers = \
 	${std_srcdir}/scoped_allocator \
 	${std_srcdir}/set \
 	${std_srcdir}/shared_mutex \
+	${std_srcdir}/source_location \
 	${std_srcdir}/span \
 	${std_srcdir}/sstream \
 	${std_srcdir}/stack \
diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
index 7ccfc5f199d..2d2ec96a925 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -630,6 +630,7 @@  namespace std
 
 #if __GNUC__ >= 7
 // Assume these are available if the compiler claims to be a recent GCC:
+# define _GLIBCXX_HAVE_BUILTIN_LINE 1
 # define _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP 1
 # define _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE 1
 # define _GLIBCXX_HAVE_BUILTIN_LAUNDER 1
@@ -637,6 +638,9 @@  namespace std
 # if __GNUC__ >= 9
 #  define _GLIBCXX_HAVE_BUILTIN_IS_CONSTANT_EVALUATED 1
 # endif
+# if __GNUC__ >= 10
+#  define _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION 1
+# endif
 #elif defined(__is_identifier) && defined(__has_builtin)
 // For non-GNU compilers:
 # if ! __is_identifier(__has_unique_object_representations)
@@ -654,6 +658,15 @@  namespace std
 # if ! __is_identifier(__is_same)
 #  define _GLIBCXX_BUILTIN_IS_SAME_AS(T, U) __is_same(T, U)
 # endif
+# if __has_builtin(__builtin_source_location)
+#  define _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION 1
+# endif
+# if __has_builtin(__builtin_LINE)
+#  define _GLIBCXX_HAVE_BUILTIN_LINE 1
+# endif
+# if __has_builtin(__builtin_COLUMN)
+#  define _GLIBCXX_HAVE_BUILTIN_COLUMN 1
+# endif
 #endif // GCC
 
 // PSTL configuration
diff --git a/libstdc++-v3/include/std/source_location b/libstdc++-v3/include/std/source_location
new file mode 100644
index 00000000000..3bf219efa81
--- /dev/null
+++ b/libstdc++-v3/include/std/source_location
@@ -0,0 +1,172 @@ 
+// Component for retrieving function, line and column source info. -*- 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 source_location
+ *  This is a Standard C++ Library header.
+ */
+
+//
+// P1208 source_location library
+// Contributed by ThePhD with <3
+//
+
+#ifndef _GLIBCXX_SOURCE_LOCATION
+#define _GLIBCXX_SOURCE_LOCATION 1
+
+#pragma GCC system_header
+
+#if __cplusplus > 201703L
+
+#include <bits/c++config.h>
+#include <cstdint>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#define __cpp_lib_source_location 201907L
+
+// use by-pointer for GCC-style __builtin_source_location;
+// use by-value for Clang-style builtins.
+#ifdef _GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION
+
+  struct source_location
+  {
+  private:
+    struct __impl
+    {
+      const char *_M_file_name;
+      const char *_M_function_name;
+      unsigned int _M_line, _M_column;
+    };
+
+  public:
+    static consteval source_location
+    current (const void *__src_loc_impl =
+	       __builtin_source_location ()) noexcept
+    {
+      source_location __ret;
+      __ret._M_data = static_cast<const __impl *>(__src_loc_impl);
+      return __ret;
+    }
+
+    constexpr
+    source_location () noexcept
+    : _M_data ()
+    { }
+
+    constexpr const char *
+    file_name () const noexcept
+    { return _M_data ? _M_data->_M_file_name : ""; }
+
+    constexpr const char *
+    function_name () const noexcept
+    { return _M_data ? _M_data->_M_function_name : ""; }
+
+    constexpr uint_least32_t
+    line () const noexcept
+    { return _M_data ? _M_data->_M_line : 0; }
+  
+    constexpr uint_least32_t
+    column () const noexcept
+    { return _M_data ? _M_data->_M_column : 0; }
+
+  private:
+    const __impl *_M_data;
+  };
+
+#elif defined(_GLIBCXX_HAVE_BUILTIN_LINE)
+
+  struct source_location
+  {
+  private:
+    struct __impl
+    {
+      const char *_M_file_name;
+      const char *_M_function_name;
+      uint_least32_t _M_line, _M_column;
+    };
+
+  public:
+    static consteval source_location
+    current (uint_least32_t __line = __builtin_LINE (),
+#ifdef _GLIBCXX_HAVE_BUILTIN_COLUMN
+	     uint_least32_t __column = __builtin_COLUMN (),
+#else
+	     uint_least32_t __column = 0,
+#endif // __builtin_COLUMN from Clang 9+
+	     const char* __file = __builtin_FILE (),
+	     const char* __function = __builtin_FUNCTION ()) noexcept
+    {
+      return source_location (__line, __column, __file, __function);
+    }
+
+    constexpr
+    source_location () noexcept
+    : _M_data()
+    {
+      _M_data._M_file_name = "";
+      _M_data._M_function_name = "";
+      _M_data._M_line = 0;
+      _M_data._M_column = 0;
+    }
+
+    constexpr const char *
+    file_name () const
+    { return _M_data._M_file_name; }
+
+    constexpr const char *
+    function_name () const
+    { return _M_data._M_function_name; }
+
+    constexpr uint_least32_t
+    line () const
+    { return _M_data._M_line; }
+  
+    constexpr uint_least32_t
+    column () const
+    { return _M_data._M_column; }
+
+  private:
+    constexpr
+    source_location (uint_least32_t __line, uint_least32_t __column,
+		     const char* __file, const char* __function) noexcept
+    : _M_data ()
+    {
+      this->_M_data._M_file_name = __file;
+      this->_M_data._M_function_name = __function;
+      this->_M_data._M_line = __line;
+      this->_M_data._M_column = __column;
+    }
+
+    const __impl _M_data;
+  };
+
+#endif // __builtin_source_location vs. __builtin_LINE + __builtin_COLUMN
+
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++20
+#endif // _GLIBCXX_SOURCE_LOCATION
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index e55a092eb89..4357d7de71c 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -196,6 +196,11 @@ 
 #endif
 #define __cpp_lib_to_array 201907L
 #endif
+#if defined(_GLIBCXX_HAVE_BUILTIN_SOURCE_LOCATION)
+# define __cpp_lib_is_constant_evaluated 201907L
+#elif defined(_GLIBCXX_HAVE_BUILTIN_LINE) && defined(_GLIBCXX_HAVE_BUILTIN_COLUMN)
+# define __cpp_lib_is_constant_evaluated 201907L
+#endif
 #endif // C++2a
 #endif // C++17
 #endif // C++14
diff --git a/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.C b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.C
new file mode 100644
index 00000000000..b3b6e5c5125
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.C
@@ -0,0 +1,137 @@ 
+// 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/>.
+
+// Example from C++ Standard Working Draft N4842, November 2019 Mailing
+// Adapted for testing.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <source_location>
+#include <string_view>
+
+struct s {
+  std::source_location member = std::source_location::current();
+  int other_member = 1;
+  
+  constexpr s(std::source_location loc = std::source_location::current())
+    : member(loc) // values of member refer to calling function
+  { }
+
+  constexpr s(int blather) : // values of member refer to this location
+    other_member(blather)
+  { }
+};
+
+constexpr std::source_location
+f(std::source_location a = std::source_location::current())
+{ return a; }
+
+constexpr std::source_location
+g()
+{
+  std::source_location c = std::source_location::current();
+  return f(c);
+}
+
+#include "std.n4842.h"
+#include <iostream>
+int main ()
+{
+  constexpr std::source_location main_sl = std::source_location::current();
+  constexpr std::source_location f_arg_sl = f(main_sl);
+  constexpr std::source_location g_sl = g();
+  constexpr std::source_location f_sl = f();
+  constexpr std::source_location h_sl = h();
+  constexpr s member_main_sl(main_sl);
+  constexpr s member_defaulted_sl(1);
+  constexpr s member_sl = s{};
+
+  using namespace std::string_view_literals;
+
+  constexpr std::string_view main_sl_fn_name(main_sl.function_name());
+  constexpr std::string_view main_sl_fi_name(main_sl.file_name());
+  static_assert(main_sl.line() == 55);
+  // closing paren of call
+  static_assert(main_sl.column() == 74);
+  static_assert(main_sl_fn_name.ends_with("main"sv));
+  static_assert(main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view f_arg_sl_fn_name(f_arg_sl.function_name());
+  constexpr std::string_view f_arg_sl_fi_name(f_arg_sl.file_name());
+  static_assert(f_arg_sl.line() == 55);
+  // closing paren of call
+  static_assert(f_arg_sl.column() == 74);
+  static_assert(f_arg_sl_fn_name.ends_with("main"sv));
+  static_assert(f_arg_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view g_sl_fn_name(g_sl.function_name());
+  constexpr std::string_view g_sl_fi_name(g_sl.file_name());
+  static_assert(g_sl.line() == 47);
+  static_assert(g_sl.column() == 58); // closing paren of call
+  static_assert(g_sl_fn_name.ends_with("g"sv));
+  static_assert(g_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view h_sl_fn_name(h_sl.function_name());
+  constexpr std::string_view h_sl_fi_name(h_sl.file_name());
+  static_assert(h_sl.line() == 23);
+  static_assert(h_sl.column() == 58); // closing paren of call
+  static_assert(h_sl_fn_name.ends_with("h"sv));
+  static_assert(h_sl_fi_name.ends_with("std.n4842.h"sv));
+
+  constexpr std::string_view member_main_sl_fn_name(member_main_sl.member.function_name());
+  constexpr std::string_view member_main_sl_fi_name(member_main_sl.member.file_name());
+  static_assert(member_main_sl.member.line() == 55);
+  static_assert(member_main_sl.member.column() == 74);
+  static_assert(member_main_sl_fn_name.ends_with("main"sv));
+  static_assert(member_main_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  // FIXME: Jakub's patch does not
+  // properly get the name of the calling function
+  // when used as a default argument,
+  // nor does it follow the example in the std
+  // FIXME: All 3 cases below are busted
+  constexpr std::string_view member_defaulted_sl_fn_name(
+    member_defaulted_sl.member.function_name());
+  constexpr std::string_view member_defaulted_sl_fi_name(
+    member_defaulted_sl.member.file_name());
+  static_assert(member_defaulted_sl.member.line() == 59);
+  // closing brace/paren of constructor
+  static_assert(member_defaulted_sl.member.column() == 29);
+  static_assert(member_defaulted_sl_fn_name.ends_with("main"sv));
+  static_assert(member_defaulted_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view member_sl_fn_name(
+    member_sl.member.function_name());
+  constexpr std::string_view member_sl_fi_name(
+    member_sl.member.file_name());
+  static_assert(member_sl.member.line() == 59);
+  // closing brace/paren of constructor
+  static_assert(member_sl.member.column() == 29);
+  static_assert(member_sl_fn_name.ends_with("main"sv));
+  static_assert(member_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  constexpr std::string_view f_sl_fn_name(f_sl.function_name());
+  constexpr std::string_view f_sl_fi_name(f_sl.file_name());
+  static_assert(f_sl.line() == 58);
+  // closing paren of call
+  static_assert(f_sl.column() == 43);
+  static_assert(f_sl_fn_name.ends_with("main"sv));
+  static_assert(f_sl_fi_name.ends_with("std.n4842.C"sv));
+
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.h b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.h
new file mode 100644
index 00000000000..50ff5c41bea
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/support/srcloc/std.n4842.h
@@ -0,0 +1,25 @@ 
+// 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/>.
+
+#include <source_location>
+
+constexpr std::source_location
+h ()
+{
+  std::source_location a = std::source_location::current();
+  return a;
+}