public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFC C++ PATCH] __builtin_source_location ()
@ 2019-11-14 20:20 Jakub Jelinek
  2019-11-14 22:25 ` Jonathan Wakely
  2019-11-15 12:32 ` [C++ " Jakub Jelinek
  0 siblings, 2 replies; 13+ messages in thread
From: Jakub Jelinek @ 2019-11-14 20:20 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely; +Cc: gcc-patches

Hi!

The following WIP patch implements __builtin_source_location (),
which returns const void pointer to a std::source_location::__impl
struct that is required to contain __file, __function, __line and __column
fields, the first two with const char * type, the latter some integral type.

I don't have testcase coverage yet and the hash map to allow sharing of
VAR_DECLs with the same location is commented out both because it
doesn't compile for some reason and because hashing on location_t
is not enough, we probably need to hash on both location_t and fndecl,
as the baz case in the following shows.

Comments?

namespace std {
  struct source_location {
    struct __impl {
      const char *__file;
      const char *__function;
      unsigned int __line, __column;
    };
    const void *__ptr;
    constexpr source_location () : __ptr (nullptr) {}
    static consteval source_location
    current (const void *__p = __builtin_source_location ()) {
      source_location __ret;
      __ret.__ptr = __p;
      return __ret;
    }
    constexpr const char *file () const {
      return static_cast <const __impl *> (__ptr)->__file;
    }
    constexpr const char *function () const {
      return static_cast <const __impl *> (__ptr)->__function;
    }
    constexpr unsigned line () const {
      return static_cast <const __impl *> (__ptr)->__line;
    }
    constexpr unsigned column () const {
      return static_cast <const __impl *> (__ptr)->__column;
    }
  };
}

using namespace std;

consteval source_location
bar (const source_location x = source_location::current ())
{
  return x;
}

void
foo (const char **p, unsigned *q)
{
  constexpr source_location s = source_location::current ();
  constexpr source_location t = bar ();
  p[0] = s.file ();
  p[1] = s.function ();
  q[0] = s.line ();
  q[1] = s.column ();
  p[2] = t.file ();
  p[3] = t.function ();
  q[2] = t.line ();
  q[3] = t.column ();
  constexpr const char *r = s.file ();
}

template <int N>
constexpr source_location
baz ()
{
  return source_location::current ();
}

constexpr source_location s1 = baz <0> ();
constexpr source_location s2 = baz <1> ();
const source_location *p1 = &s1;
const source_location *p2 = &s2;

--- gcc/cp/tree.c.jj	2019-11-13 10:54:45.437045793 +0100
+++ gcc/cp/tree.c	2019-11-14 18:11:42.391213117 +0100
@@ -445,7 +445,9 @@ builtin_valid_in_constant_expr_p (const_
   if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL)
     {
       if (fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
-			   BUILT_IN_FRONTEND))
+			     BUILT_IN_FRONTEND)
+	  || fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION,
+				BUILT_IN_FRONTEND))
 	return true;
       /* Not a built-in.  */
       return false;
--- gcc/cp/constexpr.c.jj	2019-11-13 10:54:45.426045960 +0100
+++ gcc/cp/constexpr.c	2019-11-14 18:26:40.691581038 +0100
@@ -1238,6 +1238,9 @@ cxx_eval_builtin_function_call (const co
       return boolean_true_node;
     }
 
+  if (fndecl_built_in_p (fun, CP_BUILT_IN_SOURCE_LOCATION, BUILT_IN_FRONTEND))
+    return fold_builtin_source_location (EXPR_LOCATION (t));
+
   /* Be permissive for arguments to built-ins; __builtin_constant_p should
      return constant false for a non-constant argument.  */
   constexpr_ctx new_ctx = *ctx;
--- gcc/cp/name-lookup.c.jj	2019-11-13 10:54:45.495044911 +0100
+++ gcc/cp/name-lookup.c	2019-11-14 18:38:30.765804391 +0100
@@ -5747,6 +5747,8 @@ get_std_name_hint (const char *name)
     {"shared_lock", "<shared_mutex>", cxx14},
     {"shared_mutex", "<shared_mutex>", cxx17},
     {"shared_timed_mutex", "<shared_mutex>", cxx14},
+    /* <source_location>.  */
+    {"source_location", "<source_location>", cxx2a},
     /* <sstream>.  */
     {"basic_stringbuf", "<sstream>", cxx98},
     {"basic_istringstream", "<sstream>", cxx98},
--- gcc/cp/cp-gimplify.c.jj	2019-11-06 08:58:38.036473709 +0100
+++ gcc/cp/cp-gimplify.c	2019-11-14 20:22:32.905068438 +0100
@@ -35,6 +35,9 @@ along with GCC; see the file COPYING3.
 #include "attribs.h"
 #include "asan.h"
 #include "gcc-rich-location.h"
+#include "output.h"
+#include "file-prefix-map.h"
+#include "cgraph.h"
 
 /* Forward declarations.  */
 
@@ -896,8 +899,12 @@ cp_gimplify_expr (tree *expr_p, gimple_s
 	  tree decl = cp_get_callee_fndecl_nofold (*expr_p);
 	  if (decl
 	      && fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
-				  BUILT_IN_FRONTEND))
+				    BUILT_IN_FRONTEND))
 	    *expr_p = boolean_false_node;
+	  else if (decl
+		   && fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION,
+					 BUILT_IN_FRONTEND))
+	    *expr_p = fold_builtin_source_location (EXPR_LOCATION (*expr_p));
 	}
       break;
 
@@ -2641,9 +2648,17 @@ cp_fold (tree x)
 	/* Defer folding __builtin_is_constant_evaluated.  */
 	if (callee
 	    && fndecl_built_in_p (callee, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
-				BUILT_IN_FRONTEND))
+				  BUILT_IN_FRONTEND))
 	  break;
 
+	if (callee
+	    && fndecl_built_in_p (callee, CP_BUILT_IN_SOURCE_LOCATION,
+				  BUILT_IN_FRONTEND))
+	  {
+	    x = fold_builtin_source_location (EXPR_LOCATION (x));
+	    break;
+	  }
+
 	x = copy_node (x);
 
 	m = call_expr_nargs (x);
@@ -2868,4 +2883,172 @@ process_stmt_hotness_attribute (tree std
   return std_attrs;
 }
 
+/* Helper of fold_builtin_source_location, return the
+   std::source_location::__impl type after performing verification
+   on it.  */
+
+static tree
+get_source_location_impl (location_t loc)
+{
+  tree name = get_identifier ("source_location");
+  tree decl = lookup_qualified_name (std_node, name);
+  if (TREE_CODE (decl) != TYPE_DECL)
+    {
+      auto_diagnostic_group d;
+      if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
+	qualified_name_lookup_error (std_node, name, decl, loc);
+      else
+	error ("%<std::%D%> is not a type", decl);
+      return error_mark_node;
+    }
+  name = get_identifier ("__impl");
+  tree type = TREE_TYPE (decl);
+  decl = lookup_qualified_name (type, name);
+  if (TREE_CODE (decl) != TYPE_DECL)
+    {
+      auto_diagnostic_group d;
+      if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
+	qualified_name_lookup_error (type, name, decl, loc);
+      else
+	error ("%<std::source_location::%D%> is not a type", decl);
+      return error_mark_node;
+    }
+  type = TREE_TYPE (decl);
+  if (TREE_CODE (type) != RECORD_TYPE)
+    {
+      error ("%<std::source_location::%D%> is not a class type", decl);
+      return error_mark_node;
+    }
+
+  int cnt = 0;
+  for (tree field = TYPE_FIELDS (type);
+       (field = next_initializable_field (field)) != NULL_TREE;
+       field = DECL_CHAIN (field))
+    {
+      if (DECL_NAME (field) != NULL_TREE)
+	{
+	  const char *n = IDENTIFIER_POINTER (DECL_NAME (field));
+	  if (strcmp (n, "__file") == 0 || strcmp (n, "__function") == 0)
+	    {
+	      if (TREE_TYPE (field) != const_string_type_node)
+		{
+		  error ("%<std::source_location::__impl::%D%> does not "
+			 "have %<const char *%> type", field);
+		  return error_mark_node;
+		}
+	      cnt++;
+	      continue;
+	    }
+	  else if (strcmp (n, "__line") == 0 || strcmp (n, "__column") == 0)
+	    {
+	      if (TREE_CODE (TREE_TYPE (field)) != INTEGER_TYPE)
+		{
+		  error ("%<std::source_location::__impl::%D%> does not "
+			 "have integral type", field);
+		  return error_mark_node;
+		}
+	      cnt++;
+	      continue;
+	    }
+	}
+      cnt = 0;
+      break;
+    }
+  if (cnt != 4)
+    {
+      error ("%<std::source_location::__impl%> does not contain only "
+	     "non-static data members %<__file%>, %<__function%>, "
+	     "%<__line%> and %<__column%>");
+      return error_mark_node;
+    }
+  return build_qualified_type (type, TYPE_QUAL_CONST);
+}
+
+/* static GTY(()) hash_map <location_hash, tree> *source_location_table; */
+static GTY(()) unsigned int source_location_id;
+
+/* Fold __builtin_source_location () call.  LOC is the location
+   of the call.  */
+
+tree
+fold_builtin_source_location (location_t loc)
+{
+  if (source_location_impl == NULL_TREE)
+    {
+      auto_diagnostic_group d;
+      source_location_impl = get_source_location_impl (loc);
+      if (source_location_impl == error_mark_node)
+	inform (loc, "evaluating %qs", "__builtin_source_location");
+    }
+  if (source_location_impl == error_mark_node)
+    return build_zero_cst (const_ptr_type_node);
+//  if (source_location_table)
+//    hash_map <location_hash, tree>::create_ggc (64);
+  loc = LOCATION_LOCUS (loc);
+//  tree *varp = source_location_table->get (loc);
+  tree var;
+//  if (*varp)
+//    var = *varp;
+//  else
+    {
+      char tmp_name[32];
+      ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lsrc_loc", source_location_id++);
+      var = build_decl (loc, VAR_DECL, get_identifier (tmp_name),
+			source_location_impl);
+      TREE_STATIC (var) = 1;
+      TREE_PUBLIC (var) = 0;
+      DECL_ARTIFICIAL (var) = 1;
+      DECL_IGNORED_P (var) = 1;
+      DECL_EXTERNAL (var) = 0;
+      DECL_DECLARED_CONSTEXPR_P (var) = 1;
+      DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (var) = 1;
+      layout_decl (var, 0);
+
+      vec<constructor_elt, va_gc> *v = NULL;
+      vec_alloc (v, 4);
+      for (tree field = TYPE_FIELDS (source_location_impl);
+	   (field = next_initializable_field (field)) != NULL_TREE;
+	   field = DECL_CHAIN (field))
+	{
+	  const char *n = IDENTIFIER_POINTER (DECL_NAME (field));
+	  tree val = NULL_TREE;
+	  if (strcmp (n, "__file") == 0)
+	    {
+	      if (const char *fname = LOCATION_FILE (loc))
+		{
+		  fname = remap_macro_filename (fname);
+		  val = build_string_literal (strlen (fname) + 1, fname);
+		}
+	      else
+		val = build_string_literal (1, "");
+	    }
+	  else if (strcmp (n, "__function") == 0)
+	    {
+	      const char *name = "";
+
+	      if (current_function_decl)
+		name = cxx_printable_name (current_function_decl, 0);
+
+	      val = build_string_literal (strlen (name) + 1, name);
+	    }
+	  else if (strcmp (n, "__line") == 0)
+	    val = build_int_cst (TREE_TYPE (field), LOCATION_LINE (loc));
+	  else if (strcmp (n, "__column") == 0)
+	    val = build_int_cst (TREE_TYPE (field), LOCATION_COLUMN (loc));
+	  else
+	    gcc_unreachable ();
+	  CONSTRUCTOR_APPEND_ELT (v, field, val);
+	}
+
+      tree ctor = build_constructor (source_location_impl, v);
+      TREE_CONSTANT (ctor) = 1;
+      TREE_STATIC (ctor) = 1;
+      DECL_INITIAL (var) = ctor;
+      varpool_node::finalize_decl (var);
+//    source_location_table->put (loc, var);
+    }
+
+  return build_fold_addr_expr_with_type_loc (loc, var, const_ptr_type_node);
+}
+
 #include "gt-cp-cp-gimplify.h"
--- gcc/cp/cp-tree.h.jj	2019-11-13 10:54:45.495044911 +0100
+++ gcc/cp/cp-tree.h	2019-11-14 18:44:36.632251612 +0100
@@ -204,6 +204,8 @@ enum cp_tree_index
 
     CPTI_ANY_TARG,
 
+    CPTI_SOURCE_LOCATION_IMPL,
+
     CPTI_MAX
 };
 
@@ -356,6 +358,9 @@ extern GTY(()) tree cp_global_trees[CPTI
 /* A node which matches any template argument.  */
 #define any_targ_node			cp_global_trees[CPTI_ANY_TARG]
 
+/* std::source_location::__impl class.  */
+#define source_location_impl		cp_global_trees[CPTI_SOURCE_LOCATION_IMPL]
+
 /* Node to indicate default access. This must be distinct from the
    access nodes in tree.h.  */
 
@@ -6175,6 +6180,7 @@ struct GTY((chain_next ("%h.next"))) tin
 enum cp_built_in_function {
   CP_BUILT_IN_IS_CONSTANT_EVALUATED,
   CP_BUILT_IN_INTEGER_PACK,
+  CP_BUILT_IN_SOURCE_LOCATION,
   CP_BUILT_IN_LAST
 };
 
@@ -7723,6 +7729,7 @@ extern void clear_fold_cache			(void);
 extern tree lookup_hotness_attribute		(tree);
 extern tree process_stmt_hotness_attribute	(tree, location_t);
 extern bool simple_empty_class_p		(tree, tree, tree_code);
+extern tree fold_builtin_source_location	(location_t);
 
 /* in name-lookup.c */
 extern tree strip_using_decl                    (tree);
--- gcc/cp/decl.c.jj	2019-11-12 09:09:33.598815768 +0100
+++ gcc/cp/decl.c	2019-11-14 18:10:35.918221482 +0100
@@ -4290,6 +4290,12 @@ cxx_init_decl_processing (void)
 			    BUILT_IN_FRONTEND, NULL, NULL_TREE);
   set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
 
+  tree cptr_ftype = build_function_type_list (const_ptr_type_node, NULL_TREE);
+  decl = add_builtin_function ("__builtin_source_location",
+			       cptr_ftype, CP_BUILT_IN_SOURCE_LOCATION,
+			       BUILT_IN_FRONTEND, NULL, NULL_TREE);
+  set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
+
   integer_two_node = build_int_cst (NULL_TREE, 2);
 
   /* Guess at the initial static decls size.  */

	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC C++ PATCH] __builtin_source_location ()
  2019-11-14 20:20 [RFC C++ PATCH] __builtin_source_location () Jakub Jelinek
@ 2019-11-14 22:25 ` Jonathan Wakely
  2019-11-14 22:40   ` Jakub Jelinek
  2019-11-15 12:32 ` [C++ " Jakub Jelinek
  1 sibling, 1 reply; 13+ messages in thread
From: Jonathan Wakely @ 2019-11-14 22:25 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, gcc-patches

On 14/11/19 20:34 +0100, Jakub Jelinek wrote:
>Hi!
>
>The following WIP patch implements __builtin_source_location (),
>which returns const void pointer to a std::source_location::__impl
>struct that is required to contain __file, __function, __line and __column
>fields, the first two with const char * type, the latter some integral type.
>
>I don't have testcase coverage yet and the hash map to allow sharing of
>VAR_DECLs with the same location is commented out both because it
>doesn't compile for some reason and because hashing on location_t
>is not enough, we probably need to hash on both location_t and fndecl,
>as the baz case in the following shows.
>
>Comments?
>
>namespace std {
>  struct source_location {
>    struct __impl {

Will this work if the library type is actually in an inline namespace,
such as std::__8::source_location::__impl (as for
--enable-symvers=gnu-versioned-namespace) or
std::__v1::source_location::__impl (as it probably would be in
libc++).

If I'm reading the patch correctly, it would work fine, because
qualified lookup for std::source_location would find that name even if
it's really in some inline namespace.


>      const char *__file;
>      const char *__function;
>      unsigned int __line, __column;
>    };
>    const void *__ptr;

If the magic type the compiler generates is declared in the header,
then this member might as well be 'const __impl*'.

>    constexpr source_location () : __ptr (nullptr) {}
>    static consteval source_location
>    current (const void *__p = __builtin_source_location ()) {
>      source_location __ret;
>      __ret.__ptr = __p;
>      return __ret;
>    }
>    constexpr const char *file () const {
>      return static_cast <const __impl *> (__ptr)->__file;

Not really relevant to your patch, but I'll say it here for the
benefit of others reading these mails ...

On IRC I suggested that the default constructor should set the __ptr
member to null, and these member functions should check for null, e.g.

  if (__ptr) [[likely]]
    return __ptr->__function;
  else
    return "";

The alternative is for the default constructor to call
__builtin_source_location() or refer to some static object in the
runtime library, but both options waste space. Adding a [[likely]]
branch to the accessors wastes no space and should only penalise users
who are misusing source_location by trying to get meaningful values
out of default constructed objects. If that's a bit slower I don't
care.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC C++ PATCH] __builtin_source_location ()
  2019-11-14 22:25 ` Jonathan Wakely
@ 2019-11-14 22:40   ` Jakub Jelinek
  2019-11-15 12:35     ` Jonathan Wakely
  0 siblings, 1 reply; 13+ messages in thread
From: Jakub Jelinek @ 2019-11-14 22:40 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Jason Merrill, gcc-patches

On Thu, Nov 14, 2019 at 10:15:21PM +0000, Jonathan Wakely wrote:
> > namespace std {
> >  struct source_location {
> >    struct __impl {
> 
> Will this work if the library type is actually in an inline namespace,
> such as std::__8::source_location::__impl (as for
> --enable-symvers=gnu-versioned-namespace) or
> std::__v1::source_location::__impl (as it probably would be in
> libc++).
> 
> If I'm reading the patch correctly, it would work fine, because
> qualified lookup for std::source_location would find that name even if
> it's really in some inline namespace.

I'd say so, but the unfinished testsuite coverage would need to cover it of
course.

> >      const char *__file;
> >      const char *__function;
> >      unsigned int __line, __column;
> >    };
> >    const void *__ptr;
> 
> If the magic type the compiler generates is declared in the header,
> then this member might as well be 'const __impl*'.

Yes, with the static_cast on the __builtin_source_location ()
result sure.  I can't easily make it return const std::source_location::__impl*
though, because the initialization of the builtins happens early, before
<source_location> is parsed.
And as it is a nested class, I think I can't predeclare it in the compiler.
If it would be std::__source_location_impl instead of
std::source_location::__impl, perhaps I could pretend there is
namespace std { struct __source_location_impl; }
but I bet that wouldn't work well with the inline namespaces.
So, is const void * return from the builtin ok?

	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [C++ PATCH] __builtin_source_location ()
  2019-11-14 20:20 [RFC C++ PATCH] __builtin_source_location () Jakub Jelinek
  2019-11-14 22:25 ` Jonathan Wakely
@ 2019-11-15 12:32 ` Jakub Jelinek
  2019-11-15 12:38   ` Jonathan Wakely
                     ` (3 more replies)
  1 sibling, 4 replies; 13+ messages in thread
From: Jakub Jelinek @ 2019-11-15 12:32 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely; +Cc: gcc-patches

On Thu, Nov 14, 2019 at 08:34:26PM +0100, Jakub Jelinek wrote:
> The following WIP patch implements __builtin_source_location (),
> which returns const void pointer to a std::source_location::__impl
> struct that is required to contain __file, __function, __line and __column
> fields, the first two with const char * type, the latter some integral type.

Here is hopefully final version, with the hashing implemented,
__file renamed to __file_name and __function to __function_name to match
how the standard names the methods and with testsuite coverage.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2019-11-15  Jakub Jelinek  <jakub@redhat.com>

	* cp-tree.h (enum cp_tree_index): Add CPTI_SOURCE_LOCATION_IMPL.
	(source_location_impl): Define.
	(enum cp_built_in_function): Add CP_BUILT_IN_SOURCE_LOCATION.
	(fold_builtin_source_location): Declare.
	* cp-gimplify.c: Include output.h, file-prefix-map.h and cgraph.h.
	(cp_gimplify_expr, cp_fold): Handle CP_BUILT_IN_SOURCE_LOCATION.
	Formatting fix.
	(get_source_location_impl): New function.
	(struct source_location_table_entry,
	struct source_location_table_entry_hash): New types.
	(source_location_table, source_location_id): New variables.
	(fold_builtin_source_location): New function.
	* constexpr.c (cxx_eval_builtin_function_call): Handle
	CP_BUILT_IN_SOURCE_LOCATION.
	* tree.c (builtin_valid_in_constant_expr_p): Likewise.  Formatting
	fix.
	* decl.c (cxx_init_decl_processing): Register
	__builtin_source_location.
	* name-lookup.c (get_std_name_hint): Add source_location entry.

	* g++.dg/cpp2a/srcloc1.C: New test.
	* g++.dg/cpp2a/srcloc2.C: New test.
	* g++.dg/cpp2a/srcloc3.C: New test.
	* g++.dg/cpp2a/srcloc4.C: New test.
	* g++.dg/cpp2a/srcloc5.C: New test.
	* g++.dg/cpp2a/srcloc6.C: New test.
	* g++.dg/cpp2a/srcloc7.C: New test.
	* g++.dg/cpp2a/srcloc8.C: New test.
	* g++.dg/cpp2a/srcloc9.C: New test.
	* g++.dg/cpp2a/srcloc10.C: New test.
	* g++.dg/cpp2a/srcloc11.C: New test.
	* g++.dg/cpp2a/srcloc12.C: New test.
	* g++.dg/cpp2a/srcloc13.C: New test.
	* g++.dg/cpp2a/srcloc14.C: New test.

--- gcc/cp/cp-tree.h.jj	2019-11-15 00:37:14.282250695 +0100
+++ gcc/cp/cp-tree.h	2019-11-15 09:39:58.514862699 +0100
@@ -204,6 +204,8 @@ enum cp_tree_index
 
     CPTI_ANY_TARG,
 
+    CPTI_SOURCE_LOCATION_IMPL,
+
     CPTI_MAX
 };
 
@@ -356,6 +358,9 @@ extern GTY(()) tree cp_global_trees[CPTI
 /* A node which matches any template argument.  */
 #define any_targ_node			cp_global_trees[CPTI_ANY_TARG]
 
+/* std::source_location::__impl class.  */
+#define source_location_impl		cp_global_trees[CPTI_SOURCE_LOCATION_IMPL]
+
 /* Node to indicate default access. This must be distinct from the
    access nodes in tree.h.  */
 
@@ -6175,6 +6180,7 @@ struct GTY((chain_next ("%h.next"))) tin
 enum cp_built_in_function {
   CP_BUILT_IN_IS_CONSTANT_EVALUATED,
   CP_BUILT_IN_INTEGER_PACK,
+  CP_BUILT_IN_SOURCE_LOCATION,
   CP_BUILT_IN_LAST
 };
 
@@ -7723,6 +7729,7 @@ extern void clear_fold_cache			(void);
 extern tree lookup_hotness_attribute		(tree);
 extern tree process_stmt_hotness_attribute	(tree, location_t);
 extern bool simple_empty_class_p		(tree, tree, tree_code);
+extern tree fold_builtin_source_location	(location_t);
 
 /* in name-lookup.c */
 extern tree strip_using_decl                    (tree);
--- gcc/cp/cp-gimplify.c.jj	2019-11-15 00:37:14.511247252 +0100
+++ gcc/cp/cp-gimplify.c	2019-11-15 11:23:50.574203292 +0100
@@ -35,6 +35,9 @@ along with GCC; see the file COPYING3.
 #include "attribs.h"
 #include "asan.h"
 #include "gcc-rich-location.h"
+#include "output.h"
+#include "file-prefix-map.h"
+#include "cgraph.h"
 
 /* Forward declarations.  */
 
@@ -896,8 +899,12 @@ cp_gimplify_expr (tree *expr_p, gimple_s
 	  tree decl = cp_get_callee_fndecl_nofold (*expr_p);
 	  if (decl
 	      && fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
-				  BUILT_IN_FRONTEND))
+				    BUILT_IN_FRONTEND))
 	    *expr_p = boolean_false_node;
+	  else if (decl
+		   && fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION,
+					 BUILT_IN_FRONTEND))
+	    *expr_p = fold_builtin_source_location (EXPR_LOCATION (*expr_p));
 	}
       break;
 
@@ -2641,9 +2648,17 @@ cp_fold (tree x)
 	/* Defer folding __builtin_is_constant_evaluated.  */
 	if (callee
 	    && fndecl_built_in_p (callee, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
-				BUILT_IN_FRONTEND))
+				  BUILT_IN_FRONTEND))
 	  break;
 
+	if (callee
+	    && fndecl_built_in_p (callee, CP_BUILT_IN_SOURCE_LOCATION,
+				  BUILT_IN_FRONTEND))
+	  {
+	    x = fold_builtin_source_location (EXPR_LOCATION (x));
+	    break;
+	  }
+
 	x = copy_node (x);
 
 	m = call_expr_nargs (x);
@@ -2868,4 +2883,246 @@ process_stmt_hotness_attribute (tree std
   return std_attrs;
 }
 
+/* Helper of fold_builtin_source_location, return the
+   std::source_location::__impl type after performing verification
+   on it.  */
+
+static tree
+get_source_location_impl (location_t loc)
+{
+  tree name = get_identifier ("source_location");
+  tree decl = lookup_qualified_name (std_node, name);
+  if (TREE_CODE (decl) != TYPE_DECL)
+    {
+      auto_diagnostic_group d;
+      if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
+	qualified_name_lookup_error (std_node, name, decl, loc);
+      else
+	error ("%qD is not a type", decl);
+      return error_mark_node;
+    }
+  name = get_identifier ("__impl");
+  tree type = TREE_TYPE (decl);
+  decl = lookup_qualified_name (type, name);
+  if (TREE_CODE (decl) != TYPE_DECL)
+    {
+      auto_diagnostic_group d;
+      if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
+	qualified_name_lookup_error (type, name, decl, loc);
+      else
+	error ("%qD is not a type", decl);
+      return error_mark_node;
+    }
+  type = TREE_TYPE (decl);
+  if (TREE_CODE (type) != RECORD_TYPE)
+    {
+      error ("%qD is not a class type", decl);
+      return error_mark_node;
+    }
+
+  int cnt = 0;
+  for (tree field = TYPE_FIELDS (type);
+       (field = next_initializable_field (field)) != NULL_TREE;
+       field = DECL_CHAIN (field))
+    {
+      if (DECL_NAME (field) != NULL_TREE)
+	{
+	  const char *n = IDENTIFIER_POINTER (DECL_NAME (field));
+	  if (strcmp (n, "__file_name") == 0
+	      || strcmp (n, "__function_name") == 0)
+	    {
+	      if (TREE_TYPE (field) != const_string_type_node)
+		{
+		  error ("%qD does not have %<const char *%> type", field);
+		  return error_mark_node;
+		}
+	      cnt++;
+	      continue;
+	    }
+	  else if (strcmp (n, "__line") == 0 || strcmp (n, "__column") == 0)
+	    {
+	      if (TREE_CODE (TREE_TYPE (field)) != INTEGER_TYPE)
+		{
+		  error ("%qD does not have integral type", field);
+		  return error_mark_node;
+		}
+	      cnt++;
+	      continue;
+	    }
+	}
+      cnt = 0;
+      break;
+    }
+  if (cnt != 4)
+    {
+      error ("%<std::source_location::__impl%> does not contain only "
+	     "non-static data members %<__file_name%>, %<__function_name%>, "
+	     "%<__line%> and %<__column%>");
+      return error_mark_node;
+    }
+  return build_qualified_type (type, TYPE_QUAL_CONST);
+}
+
+/* Type for source_location_table hash_set.  */
+struct GTY((for_user)) source_location_table_entry {
+  location_t loc;
+  unsigned uid;
+  tree var;
+};
+
+/* Traits class for function start hash maps below.  */
+
+struct source_location_table_entry_hash
+  : ggc_remove <source_location_table_entry>
+{
+  typedef source_location_table_entry value_type;
+  typedef source_location_table_entry compare_type;
+
+  static hashval_t
+  hash (const source_location_table_entry &ref)
+  {
+    inchash::hash hstate (0);
+    hstate.add_int (ref.loc);
+    hstate.add_int (ref.uid);
+    return hstate.end ();
+  }
+
+  static bool
+  equal (const source_location_table_entry &ref1,
+	 const source_location_table_entry &ref2)
+  {
+    return ref1.loc == ref2.loc && ref1.uid == ref2.uid;
+  }
+
+  static void
+  mark_deleted (source_location_table_entry &ref)
+  {
+    ref.loc = UNKNOWN_LOCATION;
+    ref.uid = -1U;
+    ref.var = NULL_TREE;
+  }
+
+  static void
+  mark_empty (source_location_table_entry &ref)
+  {
+    ref.loc = UNKNOWN_LOCATION;
+    ref.uid = 0;
+    ref.var = NULL_TREE;
+  }
+
+  static bool
+  is_deleted (const source_location_table_entry &ref)
+  {
+    return (ref.loc == UNKNOWN_LOCATION
+	    && ref.uid == -1U
+	    && ref.var == NULL_TREE);
+  }
+
+  static bool
+  is_empty (const source_location_table_entry &ref)
+  {
+    return (ref.loc == UNKNOWN_LOCATION
+	    && ref.uid == 0
+	    && ref.var == NULL_TREE);
+  }
+};
+
+static GTY(()) hash_table <source_location_table_entry_hash>
+  *source_location_table;
+static GTY(()) unsigned int source_location_id;
+
+/* Fold __builtin_source_location () call.  LOC is the location
+   of the call.  */
+
+tree
+fold_builtin_source_location (location_t loc)
+{
+  if (source_location_impl == NULL_TREE)
+    {
+      auto_diagnostic_group d;
+      source_location_impl = get_source_location_impl (loc);
+      if (source_location_impl == error_mark_node)
+	inform (loc, "evaluating %qs", "__builtin_source_location");
+    }
+  if (source_location_impl == error_mark_node)
+    return build_zero_cst (const_ptr_type_node);
+  if (source_location_table == NULL)
+    source_location_table
+      = hash_table <source_location_table_entry_hash>::create_ggc (64);
+  loc = LOCATION_LOCUS (loc);
+  const line_map_ordinary *map;
+  source_location_table_entry entry;
+  entry.loc
+    = linemap_resolve_location (line_table, loc, LRK_MACRO_EXPANSION_POINT,
+				&map);
+  entry.uid = current_function_decl ? DECL_UID (current_function_decl) : -1;
+  entry.var = error_mark_node;
+  source_location_table_entry *entryp
+    = source_location_table->find_slot (entry, INSERT);
+  tree var;
+  if (entryp->var)
+    var = entryp->var;
+  else
+    {
+      char tmp_name[32];
+      ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lsrc_loc", source_location_id++);
+      var = build_decl (loc, VAR_DECL, get_identifier (tmp_name),
+			source_location_impl);
+      TREE_STATIC (var) = 1;
+      TREE_PUBLIC (var) = 0;
+      DECL_ARTIFICIAL (var) = 1;
+      DECL_IGNORED_P (var) = 1;
+      DECL_EXTERNAL (var) = 0;
+      DECL_DECLARED_CONSTEXPR_P (var) = 1;
+      DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (var) = 1;
+      layout_decl (var, 0);
+
+      vec<constructor_elt, va_gc> *v = NULL;
+      vec_alloc (v, 4);
+      for (tree field = TYPE_FIELDS (source_location_impl);
+	   (field = next_initializable_field (field)) != NULL_TREE;
+	   field = DECL_CHAIN (field))
+	{
+	  const char *n = IDENTIFIER_POINTER (DECL_NAME (field));
+	  tree val = NULL_TREE;
+	  if (strcmp (n, "__file_name") == 0)
+	    {
+	      if (const char *fname = LOCATION_FILE (loc))
+		{
+		  fname = remap_macro_filename (fname);
+		  val = build_string_literal (strlen (fname) + 1, fname);
+		}
+	      else
+		val = build_string_literal (1, "");
+	    }
+	  else if (strcmp (n, "__function_name") == 0)
+	    {
+	      const char *name = "";
+
+	      if (current_function_decl)
+		name = cxx_printable_name (current_function_decl, 0);
+
+	      val = build_string_literal (strlen (name) + 1, name);
+	    }
+	  else if (strcmp (n, "__line") == 0)
+	    val = build_int_cst (TREE_TYPE (field), LOCATION_LINE (loc));
+	  else if (strcmp (n, "__column") == 0)
+	    val = build_int_cst (TREE_TYPE (field), LOCATION_COLUMN (loc));
+	  else
+	    gcc_unreachable ();
+	  CONSTRUCTOR_APPEND_ELT (v, field, val);
+	}
+
+      tree ctor = build_constructor (source_location_impl, v);
+      TREE_CONSTANT (ctor) = 1;
+      TREE_STATIC (ctor) = 1;
+      DECL_INITIAL (var) = ctor;
+      varpool_node::finalize_decl (var);
+      *entryp = entry;
+      entryp->var = var;
+    }
+
+  return build_fold_addr_expr_with_type_loc (loc, var, const_ptr_type_node);
+}
+
 #include "gt-cp-cp-gimplify.h"
--- gcc/cp/constexpr.c.jj	2019-11-15 00:37:14.239251341 +0100
+++ gcc/cp/constexpr.c	2019-11-15 09:39:58.509862775 +0100
@@ -1238,6 +1238,9 @@ cxx_eval_builtin_function_call (const co
       return boolean_true_node;
     }
 
+  if (fndecl_built_in_p (fun, CP_BUILT_IN_SOURCE_LOCATION, BUILT_IN_FRONTEND))
+    return fold_builtin_source_location (EXPR_LOCATION (t));
+
   /* Be permissive for arguments to built-ins; __builtin_constant_p should
      return constant false for a non-constant argument.  */
   constexpr_ctx new_ctx = *ctx;
--- gcc/cp/tree.c.jj	2019-11-15 00:37:14.452248140 +0100
+++ gcc/cp/tree.c	2019-11-15 09:39:58.507862806 +0100
@@ -445,7 +445,9 @@ builtin_valid_in_constant_expr_p (const_
   if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL)
     {
       if (fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
-			   BUILT_IN_FRONTEND))
+			     BUILT_IN_FRONTEND)
+	  || fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION,
+				BUILT_IN_FRONTEND))
 	return true;
       /* Not a built-in.  */
       return false;
--- gcc/cp/decl.c.jj	2019-11-15 00:37:14.355249597 +0100
+++ gcc/cp/decl.c	2019-11-15 09:39:58.516862669 +0100
@@ -4290,6 +4290,12 @@ cxx_init_decl_processing (void)
 			    BUILT_IN_FRONTEND, NULL, NULL_TREE);
   set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
 
+  tree cptr_ftype = build_function_type_list (const_ptr_type_node, NULL_TREE);
+  decl = add_builtin_function ("__builtin_source_location",
+			       cptr_ftype, CP_BUILT_IN_SOURCE_LOCATION,
+			       BUILT_IN_FRONTEND, NULL, NULL_TREE);
+  set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
+
   integer_two_node = build_int_cst (NULL_TREE, 2);
 
   /* Guess at the initial static decls size.  */
--- gcc/cp/name-lookup.c.jj	2019-11-15 00:37:14.410248771 +0100
+++ gcc/cp/name-lookup.c	2019-11-15 09:39:58.511862745 +0100
@@ -5747,6 +5747,8 @@ get_std_name_hint (const char *name)
     {"shared_lock", "<shared_mutex>", cxx14},
     {"shared_mutex", "<shared_mutex>", cxx17},
     {"shared_timed_mutex", "<shared_mutex>", cxx14},
+    /* <source_location>.  */
+    {"source_location", "<source_location>", cxx2a},
     /* <sstream>.  */
     {"basic_stringbuf", "<sstream>", cxx98},
     {"basic_istringstream", "<sstream>", cxx98},
--- gcc/testsuite/g++.dg/cpp2a/srcloc1.C.jj	2019-11-15 10:49:47.705194823 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc1.C	2019-11-15 11:43:33.203286115 +0100
@@ -0,0 +1,114 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+      const char *__file_name;
+      const char *__function_name;
+      unsigned int __line, __column;
+    };
+    const __impl *__ptr;
+    constexpr source_location () : __ptr (nullptr) {}
+    static consteval source_location
+    current (const void *__p = __builtin_source_location ()) {
+      source_location __ret;
+      __ret.__ptr = static_cast <const __impl *> (__p);
+      return __ret;
+    }
+    constexpr const char *file_name () const {
+      return __ptr ? __ptr->__file_name : "";
+    }
+    constexpr const char *function_name () const {
+      return __ptr ? __ptr->__function_name : "";
+    }
+    constexpr unsigned line () const {
+      return __ptr ? __ptr->__line : 0;
+    }
+    constexpr unsigned column () const {
+      return __ptr ? __ptr->__column : 0;
+    }
+  };
+}
+
+using namespace std;
+
+consteval source_location
+bar (const source_location x = source_location::current ())
+{
+  return x;
+}
+
+void
+foo (const char **p, unsigned *q)
+{
+  constexpr source_location s = source_location::current ();
+  constexpr source_location t = bar ();
+  p[0] = s.file_name ();
+  p[1] = s.function_name ();
+  q[0] = s.line ();
+  q[1] = s.column ();
+  p[2] = t.file_name ();
+  p[3] = t.function_name ();
+  q[2] = t.line ();
+  q[3] = t.column ();
+  constexpr const char *r = s.file_name ();
+}
+
+source_location s3 = source_location::current ();
+
+template <int N>
+constexpr source_location
+baz ()
+{
+  return source_location::current ();
+}
+
+#define A \
+  source_location s[3] = { source_location::current (), \
+			   source_location::current (), \
+			   source_location::current () }
+
+source_location *
+boo ()
+{
+  static A;
+  return &s[0];
+}
+
+constexpr source_location s1 = baz <0> ();
+constexpr source_location s2 = baz <1> ();
+const source_location *p1 = &s1;
+const source_location *p2 = &s2;
+static_assert (source_location::current ().line () == __LINE__);
+static_assert (source_location::current ().column () == 42);
+
+constexpr bool
+quux ()
+{
+  const char *file1 = source_location::current ().file_name ();
+  const char *file2 = __FILE__;
+  const char *function1 = source_location::current ().function_name ();
+  const char *function2 = __FUNCTION__;
+  int line1 = source_location::current ().line ();
+  int line2 = __LINE__ - 1;
+  int column
+    = source_location::current ().column ();
+  int i = 0;
+  for (; file1[i]; i++)
+    if (file1[i] != file2[i])
+      return false;
+  if (file2[i])
+    return false;
+  for (i = 0; function1[i]; i++)
+    if (function1[i] != function2[i])
+      return false;
+  if (function2[i])
+    return false;
+  if (line1 != line2)
+    return false;
+  if (column != 33)
+    return false;
+  return true;
+}
+
+static_assert (quux ());
--- gcc/testsuite/g++.dg/cpp2a/srcloc2.C.jj	2019-11-15 10:50:58.372122068 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc2.C	2019-11-15 11:44:12.267694376 +0100
@@ -0,0 +1,118 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  inline namespace _8 { }
+  namespace _8 {
+  struct source_location {
+    struct __impl {
+      const char *__file_name;
+      const char *__function_name;
+      unsigned int __line, __column;
+    };
+    const __impl *__ptr;
+    constexpr source_location () : __ptr (nullptr) {}
+    static consteval source_location
+    current (const void *__p = __builtin_source_location ()) {
+      source_location __ret;
+      __ret.__ptr = static_cast <const __impl *> (__p);
+      return __ret;
+    }
+    constexpr const char *file_name () const {
+      return __ptr ? __ptr->__file_name : "";
+    }
+    constexpr const char *function_name () const {
+      return __ptr ? __ptr->__function_name : "";
+    }
+    constexpr unsigned line () const {
+      return __ptr ? __ptr->__line : 0;
+    }
+    constexpr unsigned column () const {
+      return __ptr ? __ptr->__column : 0;
+    }
+  };
+  }
+}
+
+using namespace std;
+
+consteval source_location
+bar (const source_location x = source_location::current ())
+{
+  return x;
+}
+
+void
+foo (const char **p, unsigned *q)
+{
+  constexpr source_location s = source_location::current ();
+  constexpr source_location t = bar ();
+  p[0] = s.file_name ();
+  p[1] = s.function_name ();
+  q[0] = s.line ();
+  q[1] = s.column ();
+  p[2] = t.file_name ();
+  p[3] = t.function_name ();
+  q[2] = t.line ();
+  q[3] = t.column ();
+  constexpr const char *r = s.file_name ();
+}
+
+source_location s3 = source_location::current ();
+
+template <int N>
+constexpr source_location
+baz ()
+{
+  return source_location::current ();
+}
+
+#define A \
+  source_location s[3] = { source_location::current (), \
+			   source_location::current (), \
+			   source_location::current () }
+
+source_location *
+boo ()
+{
+  static A;
+  return &s[0];
+}
+
+constexpr source_location s1 = baz <0> ();
+constexpr source_location s2 = baz <1> ();
+const source_location *p1 = &s1;
+const source_location *p2 = &s2;
+
+static_assert (source_location::current ().line () == __LINE__);
+static_assert (source_location::current ().column () == 42);
+
+constexpr bool
+quux ()
+{
+  const char *file1 = source_location::current ().file_name ();
+  const char *file2 = __FILE__;
+  const char *function1 = source_location::current ().function_name ();
+  const char *function2 = __FUNCTION__;
+  int line1 = source_location::current ().line ();
+  int line2 = __LINE__ - 1;
+  int column
+    = source_location::current ().column ();
+  int i = 0;
+  for (; file1[i]; i++)
+    if (file1[i] != file2[i])
+      return false;
+  if (file2[i])
+    return false;
+  for (i = 0; function1[i]; i++)
+    if (function1[i] != function2[i])
+      return false;
+  if (function2[i])
+    return false;
+  if (line1 != line2)
+    return false;
+  if (column != 33)
+    return false;
+  return true;
+}
+
+static_assert (quux ());
--- gcc/testsuite/g++.dg/cpp2a/srcloc3.C.jj	2019-11-15 10:53:14.183060484 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc3.C	2019-11-15 11:25:03.541097184 +0100
@@ -0,0 +1,5 @@
+// { dg-do compile { target c++2a } }
+
+auto x = __builtin_source_location ();	// { dg-error "'source_location' is not a member of 'std'" }
+// { dg-message "std::source_location' is defined in header '<source_location>'; did you forget to '#include <source_location>'" "" { target *-*-* } .-1 }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-2 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc4.C.jj	2019-11-15 10:56:23.052193749 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc4.C	2019-11-15 11:25:03.541097184 +0100
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  void source_location ();
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'void std::source_location\\(\\)' is not a type" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc5.C.jj	2019-11-15 10:57:35.421095311 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc5.C	2019-11-15 11:25:03.541097184 +0100
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  typedef int source_location;
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location'\[^\n\r]*is not a class type" }
+// { dg-error "'__impl' is not a member of 'std::source_location'" "" { target *-*-* } .-1 }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-2 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc6.C.jj	2019-11-15 11:00:52.896097950 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc6.C	2019-11-15 11:25:03.541097184 +0100
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'__impl' is not a member of 'std::source_location'" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc7.C.jj	2019-11-15 11:01:26.967580801 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc7.C	2019-11-15 11:25:03.542097169 +0100
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    static void __impl ();
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl\\(\\)' is not a type" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc8.C.jj	2019-11-15 11:03:04.160105574 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc8.C	2019-11-15 11:25:03.542097169 +0100
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    typedef int __impl;
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl()' is not a class type" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc9.C.jj	2019-11-15 11:04:03.663202412 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc9.C	2019-11-15 11:25:03.542097169 +0100
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+    };
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl' does not contain only non-static data members '__file_name', '__function_name', '__line' and '__column'" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc10.C.jj	2019-11-15 11:05:09.253206861 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc10.C	2019-11-15 11:25:03.542097169 +0100
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+      const char *__file_name, *__function_name;
+      int __foo, __line, __column;
+    };
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl' does not contain only non-static data members '__file_name', '__function_name', '__line' and '__column'" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc11.C.jj	2019-11-15 11:06:01.856408428 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc11.C	2019-11-15 11:25:03.542097169 +0100
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+      const char *__file_name, *__function_name;
+      int __line;
+    };
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl' does not contain only non-static data members '__file_name', '__function_name', '__line' and '__column'" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc12.C.jj	2019-11-15 11:06:25.999041982 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc12.C	2019-11-15 11:25:03.543097153 +0100
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+      const void *__file_name;
+      const char *__function_name;
+      int __line, __column;
+    };
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl::__file_name' does not have 'const char \\*' type" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc13.C.jj	2019-11-15 11:18:34.184999454 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc13.C	2019-11-15 11:25:03.543097153 +0100
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+      const char *__file_name;
+      const char *__function_name;
+      float __line;
+      int __column;
+    };
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl::__line' does not have integral type" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc14.C.jj	2019-11-15 11:19:51.561826493 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc14.C	2019-11-15 11:25:03.543097153 +0100
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+      // Test that ordering doesn't matter
+      long long __column;
+      const char *__file_name;
+      int __line;
+      const char *__function_name;
+    };
+  };
+}
+
+auto x = __builtin_source_location ();


	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [RFC C++ PATCH] __builtin_source_location ()
  2019-11-14 22:40   ` Jakub Jelinek
@ 2019-11-15 12:35     ` Jonathan Wakely
  0 siblings, 0 replies; 13+ messages in thread
From: Jonathan Wakely @ 2019-11-15 12:35 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, gcc-patches

On 14/11/19 23:39 +0100, Jakub Jelinek wrote:
>On Thu, Nov 14, 2019 at 10:15:21PM +0000, Jonathan Wakely wrote:
>> > namespace std {
>> >  struct source_location {
>> >    struct __impl {
>>
>> Will this work if the library type is actually in an inline namespace,
>> such as std::__8::source_location::__impl (as for
>> --enable-symvers=gnu-versioned-namespace) or
>> std::__v1::source_location::__impl (as it probably would be in
>> libc++).
>>
>> If I'm reading the patch correctly, it would work fine, because
>> qualified lookup for std::source_location would find that name even if
>> it's really in some inline namespace.
>
>I'd say so, but the unfinished testsuite coverage would need to cover it of
>course.
>
>> >      const char *__file;
>> >      const char *__function;
>> >      unsigned int __line, __column;
>> >    };
>> >    const void *__ptr;
>>
>> If the magic type the compiler generates is declared in the header,
>> then this member might as well be 'const __impl*'.
>
>Yes, with the static_cast on the __builtin_source_location ()
>result sure.  I can't easily make it return const std::source_location::__impl*
>though, because the initialization of the builtins happens early, before
><source_location> is parsed.
>And as it is a nested class, I think I can't predeclare it in the compiler.
>If it would be std::__source_location_impl instead of
>std::source_location::__impl, perhaps I could pretend there is
>namespace std { struct __source_location_impl; }
>but I bet that wouldn't work well with the inline namespaces.
>So, is const void * return from the builtin ok?

Yes, that seems fine. The library can just do the cast once and store
the result, instead of casting it on every use.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [C++ PATCH] __builtin_source_location ()
  2019-11-15 12:32 ` [C++ " Jakub Jelinek
@ 2019-11-15 12:38   ` Jonathan Wakely
  2019-11-15 12:55     ` Jakub Jelinek
  2019-11-15 14:05   ` David Malcolm
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 13+ messages in thread
From: Jonathan Wakely @ 2019-11-15 12:38 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, gcc-patches

On 15/11/19 13:28 +0100, Jakub Jelinek wrote:
>On Thu, Nov 14, 2019 at 08:34:26PM +0100, Jakub Jelinek wrote:
>> The following WIP patch implements __builtin_source_location (),
>> which returns const void pointer to a std::source_location::__impl
>> struct that is required to contain __file, __function, __line and __column
>> fields, the first two with const char * type, the latter some integral type.
>
>Here is hopefully final version, with the hashing implemented,
>__file renamed to __file_name and __function to __function_name to match
>how the standard names the methods and with testsuite coverage.

The libstdc++ naming convention says the data members should be
_M_file_name, _M_line etc.

Since this is just a normal library type now, not defined by the
compiler, I think we should follow the library convention (sorry for
not noticing that sooner).


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [C++ PATCH] __builtin_source_location ()
  2019-11-15 12:38   ` Jonathan Wakely
@ 2019-11-15 12:55     ` Jakub Jelinek
  2019-11-15 14:06       ` Jonathan Wakely
  0 siblings, 1 reply; 13+ messages in thread
From: Jakub Jelinek @ 2019-11-15 12:55 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Jason Merrill, gcc-patches

On Fri, Nov 15, 2019 at 12:35:22PM +0000, Jonathan Wakely wrote:
> On 15/11/19 13:28 +0100, Jakub Jelinek wrote:
> > On Thu, Nov 14, 2019 at 08:34:26PM +0100, Jakub Jelinek wrote:
> > > The following WIP patch implements __builtin_source_location (),
> > > which returns const void pointer to a std::source_location::__impl
> > > struct that is required to contain __file, __function, __line and __column
> > > fields, the first two with const char * type, the latter some integral type.
> > 
> > Here is hopefully final version, with the hashing implemented,
> > __file renamed to __file_name and __function to __function_name to match
> > how the standard names the methods and with testsuite coverage.
> 
> The libstdc++ naming convention says the data members should be
> _M_file_name, _M_line etc.
> 
> Since this is just a normal library type now, not defined by the
> compiler, I think we should follow the library convention (sorry for
> not noticing that sooner).

I guess it depends on what are the chances other compilers will implement
the same builtin, because doesn't say libc++ use __name rather than
_M_name convention?
Yet another option would be for the builtin to accept either
_M_file_name or __file_name, could be handled by
  const char *n = IDENTIFIER_POINTER (DECL_NAME (field));
  if (strncmp (n, "_M_", 3) == 0)
    n += 3;
  else if (strncmp (n, "__", 2) == 0)
    n += 2;
  else
    n = "";
and then do the comparisons without __ in the patch.

	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [C++ PATCH] __builtin_source_location ()
  2019-11-15 12:32 ` [C++ " Jakub Jelinek
  2019-11-15 12:38   ` Jonathan Wakely
@ 2019-11-15 14:05   ` David Malcolm
  2019-11-15 14:26     ` Jakub Jelinek
  2019-12-03 15:19   ` Patch ping (was Re: [C++ PATCH] __builtin_source_location ()) Jakub Jelinek
  2019-12-03 20:37   ` [C++ PATCH] __builtin_source_location () Jason Merrill
  3 siblings, 1 reply; 13+ messages in thread
From: David Malcolm @ 2019-11-15 14:05 UTC (permalink / raw)
  To: Jakub Jelinek, Jason Merrill, Jonathan Wakely; +Cc: gcc-patches

On Fri, 2019-11-15 at 13:28 +0100, Jakub Jelinek wrote:
> On Thu, Nov 14, 2019 at 08:34:26PM +0100, Jakub Jelinek wrote:
> > The following WIP patch implements __builtin_source_location (),
> > which returns const void pointer to a std::source_location::__impl
> > struct that is required to contain __file, __function, __line and
> > __column
> > fields, the first two with const char * type, the latter some
> > integral type.
> 
> Here is hopefully final version, with the hashing implemented,
> __file renamed to __file_name and __function to __function_name to
> match
> how the standard names the methods and with testsuite coverage.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

[...snip...]

> --- gcc/cp/cp-gimplify.c.jj	2019-11-15 00:37:14.511247252 +0100
> +++ gcc/cp/cp-gimplify.c	2019-11-15 11:23:50.574203292 +0100
[...]
> @@ -2868,4 +2883,246 @@ process_stmt_hotness_attribute (tree std
>    return std_attrs;
>  }
>  
> +/* Helper of fold_builtin_source_location, return the
> +   std::source_location::__impl type after performing verification
> +   on it.  */
> +
> +static tree
> +get_source_location_impl (location_t loc)
> +{

FWIW, I found this function confusing at first, and wondered what the
purpose of LOC was (given that the function is building a type, rather
than an instance of that type).

Maybe add this to the leading comment:
  "LOC is used for reporting any errors."
(and if so, perhaps replace the various "error" with "error_at", though
that's rather academic).

Maybe rename the function to "get_source_location_impl_type" to
emphasize the distinction?

Hope this is constructive
Dave


> +  tree name = get_identifier ("source_location");
> +  tree decl = lookup_qualified_name (std_node, name);
> +  if (TREE_CODE (decl) != TYPE_DECL)
> +    {
> +      auto_diagnostic_group d;
> +      if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
> +	qualified_name_lookup_error (std_node, name, decl, loc);
> +      else
> +	error ("%qD is not a type", decl);
> +      return error_mark_node;
> +    }
> +  name = get_identifier ("__impl");
> +  tree type = TREE_TYPE (decl);
> +  decl = lookup_qualified_name (type, name);
> +  if (TREE_CODE (decl) != TYPE_DECL)
> +    {
> +      auto_diagnostic_group d;
> +      if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
> +	qualified_name_lookup_error (type, name, decl, loc);
> +      else
> +	error ("%qD is not a type", decl);
> +      return error_mark_node;
> +    }
> +  type = TREE_TYPE (decl);
> +  if (TREE_CODE (type) != RECORD_TYPE)
> +    {
> +      error ("%qD is not a class type", decl);
> +      return error_mark_node;
> +    }
> +
> +  int cnt = 0;
> +  for (tree field = TYPE_FIELDS (type);
> +       (field = next_initializable_field (field)) != NULL_TREE;
> +       field = DECL_CHAIN (field))
> +    {
> +      if (DECL_NAME (field) != NULL_TREE)
> +	{
> +	  const char *n = IDENTIFIER_POINTER (DECL_NAME (field));
> +	  if (strcmp (n, "__file_name") == 0
> +	      || strcmp (n, "__function_name") == 0)
> +	    {
> +	      if (TREE_TYPE (field) != const_string_type_node)
> +		{
> +		  error ("%qD does not have %<const char *%> type",
> field);
> +		  return error_mark_node;
> +		}
> +	      cnt++;
> +	      continue;
> +	    }
> +	  else if (strcmp (n, "__line") == 0 || strcmp (n, "__column")
> == 0)
> +	    {
> +	      if (TREE_CODE (TREE_TYPE (field)) != INTEGER_TYPE)
> +		{
> +		  error ("%qD does not have integral type", field);
> +		  return error_mark_node;
> +		}
> +	      cnt++;
> +	      continue;
> +	    }
> +	}
> +      cnt = 0;
> +      break;
> +    }
> +  if (cnt != 4)
> +    {
> +      error ("%<std::source_location::__impl%> does not contain only
> "
> +	     "non-static data members %<__file_name%>,
> %<__function_name%>, "
> +	     "%<__line%> and %<__column%>");
> +      return error_mark_node;
> +    }
> +  return build_qualified_type (type, TYPE_QUAL_CONST);
> +}

[...snip...]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [C++ PATCH] __builtin_source_location ()
  2019-11-15 12:55     ` Jakub Jelinek
@ 2019-11-15 14:06       ` Jonathan Wakely
  0 siblings, 0 replies; 13+ messages in thread
From: Jonathan Wakely @ 2019-11-15 14:06 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, gcc-patches

On 15/11/19 13:49 +0100, Jakub Jelinek wrote:
>On Fri, Nov 15, 2019 at 12:35:22PM +0000, Jonathan Wakely wrote:
>> On 15/11/19 13:28 +0100, Jakub Jelinek wrote:
>> > On Thu, Nov 14, 2019 at 08:34:26PM +0100, Jakub Jelinek wrote:
>> > > The following WIP patch implements __builtin_source_location (),
>> > > which returns const void pointer to a std::source_location::__impl
>> > > struct that is required to contain __file, __function, __line and __column
>> > > fields, the first two with const char * type, the latter some integral type.
>> >
>> > Here is hopefully final version, with the hashing implemented,
>> > __file renamed to __file_name and __function to __function_name to match
>> > how the standard names the methods and with testsuite coverage.
>>
>> The libstdc++ naming convention says the data members should be
>> _M_file_name, _M_line etc.
>>
>> Since this is just a normal library type now, not defined by the
>> compiler, I think we should follow the library convention (sorry for
>> not noticing that sooner).
>
>I guess it depends on what are the chances other compilers will implement
>the same builtin, because doesn't say libc++ use __name rather than
>_M_name convention?

Yes, that's what libc++ uses, but I get the impression Clang isn't
going to add this built-in anyway.

>Yet another option would be for the builtin to accept either
>_M_file_name or __file_name, could be handled by
>  const char *n = IDENTIFIER_POINTER (DECL_NAME (field));
>  if (strncmp (n, "_M_", 3) == 0)
>    n += 3;
>  else if (strncmp (n, "__", 2) == 0)
>    n += 2;
>  else
>    n = "";
>and then do the comparisons without __ in the patch.

My inclination is YAGNI. At this point, a libc++ implementation that
would want to use __builtin_source_location when compiled with GCC is
hypothetical, and would already need various #if conditions around it.

BCCing libc++ maintainers in case they want to request that GCC's
built-in pre-emptively support a std::source_location::__impl type
that uses __ prefixes on its data members. For more context see
https://gcc.gnu.org/ml/gcc-patches/2019-11/msg01389.html and the rest
of the thread.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [C++ PATCH] __builtin_source_location ()
  2019-11-15 14:05   ` David Malcolm
@ 2019-11-15 14:26     ` Jakub Jelinek
  0 siblings, 0 replies; 13+ messages in thread
From: Jakub Jelinek @ 2019-11-15 14:26 UTC (permalink / raw)
  To: David Malcolm; +Cc: Jason Merrill, Jonathan Wakely, gcc-patches

On Fri, Nov 15, 2019 at 09:04:17AM -0500, David Malcolm wrote:
> > +/* Helper of fold_builtin_source_location, return the
> > +   std::source_location::__impl type after performing verification
> > +   on it.  */
> > +
> > +static tree
> > +get_source_location_impl (location_t loc)
> > +{
> 
> FWIW, I found this function confusing at first, and wondered what the
> purpose of LOC was (given that the function is building a type, rather
> than an instance of that type).
> 
> Maybe add this to the leading comment:
>   "LOC is used for reporting any errors."
> (and if so, perhaps replace the various "error" with "error_at", though
> that's rather academic).
> 
> Maybe rename the function to "get_source_location_impl_type" to
> emphasize the distinction?

Consider it done.

	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Patch ping (was Re: [C++ PATCH] __builtin_source_location ())
  2019-11-15 12:32 ` [C++ " Jakub Jelinek
  2019-11-15 12:38   ` Jonathan Wakely
  2019-11-15 14:05   ` David Malcolm
@ 2019-12-03 15:19   ` Jakub Jelinek
  2019-12-03 20:37   ` [C++ PATCH] __builtin_source_location () Jason Merrill
  3 siblings, 0 replies; 13+ messages in thread
From: Jakub Jelinek @ 2019-12-03 15:19 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely; +Cc: gcc-patches

Hi!

On Fri, Nov 15, 2019 at 01:28:17PM +0100, Jakub Jelinek wrote:
> On Thu, Nov 14, 2019 at 08:34:26PM +0100, Jakub Jelinek wrote:
> > The following WIP patch implements __builtin_source_location (),
> > which returns const void pointer to a std::source_location::__impl
> > struct that is required to contain __file, __function, __line and __column
> > fields, the first two with const char * type, the latter some integral type.
> 
> Here is hopefully final version, with the hashing implemented,
> __file renamed to __file_name and __function to __function_name to match
> how the standard names the methods and with testsuite coverage.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

I'd like to ping this patch.
I know David and Jonathan had comments on the patch and can try to
incorporate them, but more importantly I'd like to ask whether we want to
add this at all or wait till GCC 11 and add something else.
Yet another option would be make it clear that the builtin is a temporary
thing until we implement something different and then would be removed,
say by reporting error if the builtin is used anywhere but in default
argument of std::source_location::current or something similar; I mean if
the ABI is sound, but we might have __builtin_constexpr_force_static or
whatever else or some new expression form one day and replace the builtin
uses with that.

> 2019-11-15  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* cp-tree.h (enum cp_tree_index): Add CPTI_SOURCE_LOCATION_IMPL.
> 	(source_location_impl): Define.
> 	(enum cp_built_in_function): Add CP_BUILT_IN_SOURCE_LOCATION.
> 	(fold_builtin_source_location): Declare.
> 	* cp-gimplify.c: Include output.h, file-prefix-map.h and cgraph.h.
> 	(cp_gimplify_expr, cp_fold): Handle CP_BUILT_IN_SOURCE_LOCATION.
> 	Formatting fix.
> 	(get_source_location_impl): New function.
> 	(struct source_location_table_entry,
> 	struct source_location_table_entry_hash): New types.
> 	(source_location_table, source_location_id): New variables.
> 	(fold_builtin_source_location): New function.
> 	* constexpr.c (cxx_eval_builtin_function_call): Handle
> 	CP_BUILT_IN_SOURCE_LOCATION.
> 	* tree.c (builtin_valid_in_constant_expr_p): Likewise.  Formatting
> 	fix.
> 	* decl.c (cxx_init_decl_processing): Register
> 	__builtin_source_location.
> 	* name-lookup.c (get_std_name_hint): Add source_location entry.
> 
> 	* g++.dg/cpp2a/srcloc1.C: New test.
> 	* g++.dg/cpp2a/srcloc2.C: New test.
> 	* g++.dg/cpp2a/srcloc3.C: New test.
> 	* g++.dg/cpp2a/srcloc4.C: New test.
> 	* g++.dg/cpp2a/srcloc5.C: New test.
> 	* g++.dg/cpp2a/srcloc6.C: New test.
> 	* g++.dg/cpp2a/srcloc7.C: New test.
> 	* g++.dg/cpp2a/srcloc8.C: New test.
> 	* g++.dg/cpp2a/srcloc9.C: New test.
> 	* g++.dg/cpp2a/srcloc10.C: New test.
> 	* g++.dg/cpp2a/srcloc11.C: New test.
> 	* g++.dg/cpp2a/srcloc12.C: New test.
> 	* g++.dg/cpp2a/srcloc13.C: New test.
> 	* g++.dg/cpp2a/srcloc14.C: New test.

	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [C++ PATCH] __builtin_source_location ()
  2019-11-15 12:32 ` [C++ " Jakub Jelinek
                     ` (2 preceding siblings ...)
  2019-12-03 15:19   ` Patch ping (was Re: [C++ PATCH] __builtin_source_location ()) Jakub Jelinek
@ 2019-12-03 20:37   ` Jason Merrill
  2019-12-03 21:02     ` Jakub Jelinek
  3 siblings, 1 reply; 13+ messages in thread
From: Jason Merrill @ 2019-12-03 20:37 UTC (permalink / raw)
  To: Jakub Jelinek, Jonathan Wakely; +Cc: gcc-patches

On 11/15/19 7:28 AM, Jakub Jelinek wrote:
> +  loc = LOCATION_LOCUS (loc);
...
> +  entry.loc
> +    = linemap_resolve_location (line_table, loc, LRK_MACRO_EXPANSION_POINT,
> +				&map);

You don't need LOCATION_LOCUS if you're calling 
linemap_resolve_location.  LGTM with that change and David's.

> I know David and Jonathan had comments on the patch and can try to
> incorporate them, but more importantly I'd like to ask whether we want to
> add this at all or wait till GCC 11 and add something else.
> Yet another option would be make it clear that the builtin is a temporary
> thing until we implement something different and then would be removed,
> say by reporting error if the builtin is used anywhere but in default
> argument of std::source_location::current or something similar; I mean if
> the ABI is sound, but we might have __builtin_constexpr_force_static or
> whatever else or some new expression form one day and replace the builtin
> uses with that.

I don't think we need to worry about enforcement; we say in general that 
C++20 support is experimental, and we don't try to maintain 
compatibility; even more so for internal details like this.

Jason

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [C++ PATCH] __builtin_source_location ()
  2019-12-03 20:37   ` [C++ PATCH] __builtin_source_location () Jason Merrill
@ 2019-12-03 21:02     ` Jakub Jelinek
  0 siblings, 0 replies; 13+ messages in thread
From: Jakub Jelinek @ 2019-12-03 21:02 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, gcc-patches

On Tue, Dec 03, 2019 at 03:37:41PM -0500, Jason Merrill wrote:
> On 11/15/19 7:28 AM, Jakub Jelinek wrote:
> > +  loc = LOCATION_LOCUS (loc);
> ...
> > +  entry.loc
> > +    = linemap_resolve_location (line_table, loc, LRK_MACRO_EXPANSION_POINT,
> > +				&map);
> 
> You don't need LOCATION_LOCUS if you're calling linemap_resolve_location.
> LGTM with that change and David's.

I had to apply also Jon's suggestion to use _M_* names of the members
instead of __* names (didn't use the variant that would support both), while
__impl remains with two underscores.  Below is what I'll be retesting.

> > I know David and Jonathan had comments on the patch and can try to
> > incorporate them, but more importantly I'd like to ask whether we want to
> > add this at all or wait till GCC 11 and add something else.
> > Yet another option would be make it clear that the builtin is a temporary
> > thing until we implement something different and then would be removed,
> > say by reporting error if the builtin is used anywhere but in default
> > argument of std::source_location::current or something similar; I mean if
> > the ABI is sound, but we might have __builtin_constexpr_force_static or
> > whatever else or some new expression form one day and replace the builtin
> > uses with that.
> 
> I don't think we need to worry about enforcement; we say in general that
> C++20 support is experimental, and we don't try to maintain compatibility;
> even more so for internal details like this.

2019-12-03  Jakub Jelinek  <jakub@redhat.com>

	* cp-tree.h (enum cp_tree_index): Add CPTI_SOURCE_LOCATION_IMPL.
	(source_location_impl): Define.
	(enum cp_built_in_function): Add CP_BUILT_IN_SOURCE_LOCATION.
	(fold_builtin_source_location): Declare.
	* cp-gimplify.c: Include output.h, file-prefix-map.h and cgraph.h.
	(cp_gimplify_expr, cp_fold): Handle CP_BUILT_IN_SOURCE_LOCATION.
	Formatting fix.
	(get_source_location_impl_type): New function.
	(struct source_location_table_entry,
	struct source_location_table_entry_hash): New types.
	(source_location_table, source_location_id): New variables.
	(fold_builtin_source_location): New function.
	* constexpr.c (cxx_eval_builtin_function_call): Handle
	CP_BUILT_IN_SOURCE_LOCATION.
	* tree.c (builtin_valid_in_constant_expr_p): Likewise.  Formatting
	fix.
	* decl.c (cxx_init_decl_processing): Register
	__builtin_source_location.
	* name-lookup.c (get_std_name_hint): Add source_location entry.

	* g++.dg/cpp2a/srcloc1.C: New test.
	* g++.dg/cpp2a/srcloc2.C: New test.
	* g++.dg/cpp2a/srcloc3.C: New test.
	* g++.dg/cpp2a/srcloc4.C: New test.
	* g++.dg/cpp2a/srcloc5.C: New test.
	* g++.dg/cpp2a/srcloc6.C: New test.
	* g++.dg/cpp2a/srcloc7.C: New test.
	* g++.dg/cpp2a/srcloc8.C: New test.
	* g++.dg/cpp2a/srcloc9.C: New test.
	* g++.dg/cpp2a/srcloc10.C: New test.
	* g++.dg/cpp2a/srcloc11.C: New test.
	* g++.dg/cpp2a/srcloc12.C: New test.
	* g++.dg/cpp2a/srcloc13.C: New test.
	* g++.dg/cpp2a/srcloc14.C: New test.

--- gcc/cp/cp-tree.h.jj	2019-12-03 20:21:29.743476880 +0100
+++ gcc/cp/cp-tree.h	2019-12-03 21:45:31.807989738 +0100
@@ -204,6 +204,8 @@ enum cp_tree_index
 
     CPTI_ANY_TARG,
 
+    CPTI_SOURCE_LOCATION_IMPL,
+
     CPTI_MAX
 };
 
@@ -356,6 +358,9 @@ extern GTY(()) tree cp_global_trees[CPTI
 /* A node which matches any template argument.  */
 #define any_targ_node			cp_global_trees[CPTI_ANY_TARG]
 
+/* std::source_location::__impl class.  */
+#define source_location_impl		cp_global_trees[CPTI_SOURCE_LOCATION_IMPL]
+
 /* Node to indicate default access. This must be distinct from the
    access nodes in tree.h.  */
 
@@ -6182,6 +6187,7 @@ struct GTY((chain_next ("%h.next"))) tin
 enum cp_built_in_function {
   CP_BUILT_IN_IS_CONSTANT_EVALUATED,
   CP_BUILT_IN_INTEGER_PACK,
+  CP_BUILT_IN_SOURCE_LOCATION,
   CP_BUILT_IN_LAST
 };
 
@@ -7735,6 +7741,7 @@ extern void clear_fold_cache			(void);
 extern tree lookup_hotness_attribute		(tree);
 extern tree process_stmt_hotness_attribute	(tree, location_t);
 extern bool simple_empty_class_p		(tree, tree, tree_code);
+extern tree fold_builtin_source_location	(location_t);
 
 /* in name-lookup.c */
 extern tree strip_using_decl                    (tree);
--- gcc/cp/cp-gimplify.c.jj	2019-11-27 17:26:57.233013947 +0100
+++ gcc/cp/cp-gimplify.c	2019-12-03 21:52:31.720546585 +0100
@@ -35,6 +35,9 @@ along with GCC; see the file COPYING3.
 #include "attribs.h"
 #include "asan.h"
 #include "gcc-rich-location.h"
+#include "output.h"
+#include "file-prefix-map.h"
+#include "cgraph.h"
 
 /* Forward declarations.  */
 
@@ -896,8 +899,12 @@ cp_gimplify_expr (tree *expr_p, gimple_s
 	  tree decl = cp_get_callee_fndecl_nofold (*expr_p);
 	  if (decl
 	      && fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
-				  BUILT_IN_FRONTEND))
+				    BUILT_IN_FRONTEND))
 	    *expr_p = boolean_false_node;
+	  else if (decl
+		   && fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION,
+					 BUILT_IN_FRONTEND))
+	    *expr_p = fold_builtin_source_location (EXPR_LOCATION (*expr_p));
 	}
       break;
 
@@ -2657,9 +2664,17 @@ cp_fold (tree x)
 	/* Defer folding __builtin_is_constant_evaluated.  */
 	if (callee
 	    && fndecl_built_in_p (callee, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
-				BUILT_IN_FRONTEND))
+				  BUILT_IN_FRONTEND))
 	  break;
 
+	if (callee
+	    && fndecl_built_in_p (callee, CP_BUILT_IN_SOURCE_LOCATION,
+				  BUILT_IN_FRONTEND))
+	  {
+	    x = fold_builtin_source_location (EXPR_LOCATION (x));
+	    break;
+	  }
+
 	x = copy_node (x);
 
 	m = call_expr_nargs (x);
@@ -2884,4 +2899,246 @@ process_stmt_hotness_attribute (tree std
   return std_attrs;
 }
 
+/* Helper of fold_builtin_source_location, return the
+   std::source_location::__impl type after performing verification
+   on it.  LOC is used for reporting any errors.  */
+
+static tree
+get_source_location_impl_type (location_t loc)
+{
+  tree name = get_identifier ("source_location");
+  tree decl = lookup_qualified_name (std_node, name);
+  if (TREE_CODE (decl) != TYPE_DECL)
+    {
+      auto_diagnostic_group d;
+      if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
+	qualified_name_lookup_error (std_node, name, decl, loc);
+      else
+	error_at (loc, "%qD is not a type", decl);
+      return error_mark_node;
+    }
+  name = get_identifier ("__impl");
+  tree type = TREE_TYPE (decl);
+  decl = lookup_qualified_name (type, name);
+  if (TREE_CODE (decl) != TYPE_DECL)
+    {
+      auto_diagnostic_group d;
+      if (decl == error_mark_node || TREE_CODE (decl) == TREE_LIST)
+	qualified_name_lookup_error (type, name, decl, loc);
+      else
+	error_at (loc, "%qD is not a type", decl);
+      return error_mark_node;
+    }
+  type = TREE_TYPE (decl);
+  if (TREE_CODE (type) != RECORD_TYPE)
+    {
+      error_at (loc, "%qD is not a class type", decl);
+      return error_mark_node;
+    }
+
+  int cnt = 0;
+  for (tree field = TYPE_FIELDS (type);
+       (field = next_initializable_field (field)) != NULL_TREE;
+       field = DECL_CHAIN (field))
+    {
+      if (DECL_NAME (field) != NULL_TREE)
+	{
+	  const char *n = IDENTIFIER_POINTER (DECL_NAME (field));
+	  if (strcmp (n, "_M_file_name") == 0
+	      || strcmp (n, "_M_function_name") == 0)
+	    {
+	      if (TREE_TYPE (field) != const_string_type_node)
+		{
+		  error_at (loc, "%qD does not have %<const char *%> type",
+			    field);
+		  return error_mark_node;
+		}
+	      cnt++;
+	      continue;
+	    }
+	  else if (strcmp (n, "_M_line") == 0 || strcmp (n, "_M_column") == 0)
+	    {
+	      if (TREE_CODE (TREE_TYPE (field)) != INTEGER_TYPE)
+		{
+		  error_at (loc, "%qD does not have integral type", field);
+		  return error_mark_node;
+		}
+	      cnt++;
+	      continue;
+	    }
+	}
+      cnt = 0;
+      break;
+    }
+  if (cnt != 4)
+    {
+      error_at (loc, "%<std::source_location::__impl%> does not contain only "
+		     "non-static data members %<_M_file_name%>, "
+		     "%<_M_function_name%>, %<_M_line%> and %<_M_column%>");
+      return error_mark_node;
+    }
+  return build_qualified_type (type, TYPE_QUAL_CONST);
+}
+
+/* Type for source_location_table hash_set.  */
+struct GTY((for_user)) source_location_table_entry {
+  location_t loc;
+  unsigned uid;
+  tree var;
+};
+
+/* Traits class for function start hash maps below.  */
+
+struct source_location_table_entry_hash
+  : ggc_remove <source_location_table_entry>
+{
+  typedef source_location_table_entry value_type;
+  typedef source_location_table_entry compare_type;
+
+  static hashval_t
+  hash (const source_location_table_entry &ref)
+  {
+    inchash::hash hstate (0);
+    hstate.add_int (ref.loc);
+    hstate.add_int (ref.uid);
+    return hstate.end ();
+  }
+
+  static bool
+  equal (const source_location_table_entry &ref1,
+	 const source_location_table_entry &ref2)
+  {
+    return ref1.loc == ref2.loc && ref1.uid == ref2.uid;
+  }
+
+  static void
+  mark_deleted (source_location_table_entry &ref)
+  {
+    ref.loc = UNKNOWN_LOCATION;
+    ref.uid = -1U;
+    ref.var = NULL_TREE;
+  }
+
+  static void
+  mark_empty (source_location_table_entry &ref)
+  {
+    ref.loc = UNKNOWN_LOCATION;
+    ref.uid = 0;
+    ref.var = NULL_TREE;
+  }
+
+  static bool
+  is_deleted (const source_location_table_entry &ref)
+  {
+    return (ref.loc == UNKNOWN_LOCATION
+	    && ref.uid == -1U
+	    && ref.var == NULL_TREE);
+  }
+
+  static bool
+  is_empty (const source_location_table_entry &ref)
+  {
+    return (ref.loc == UNKNOWN_LOCATION
+	    && ref.uid == 0
+	    && ref.var == NULL_TREE);
+  }
+};
+
+static GTY(()) hash_table <source_location_table_entry_hash>
+  *source_location_table;
+static GTY(()) unsigned int source_location_id;
+
+/* Fold __builtin_source_location () call.  LOC is the location
+   of the call.  */
+
+tree
+fold_builtin_source_location (location_t loc)
+{
+  if (source_location_impl == NULL_TREE)
+    {
+      auto_diagnostic_group d;
+      source_location_impl = get_source_location_impl_type (loc);
+      if (source_location_impl == error_mark_node)
+	inform (loc, "evaluating %qs", "__builtin_source_location");
+    }
+  if (source_location_impl == error_mark_node)
+    return build_zero_cst (const_ptr_type_node);
+  if (source_location_table == NULL)
+    source_location_table
+      = hash_table <source_location_table_entry_hash>::create_ggc (64);
+  const line_map_ordinary *map;
+  source_location_table_entry entry;
+  entry.loc
+    = linemap_resolve_location (line_table, loc, LRK_MACRO_EXPANSION_POINT,
+				&map);
+  entry.uid = current_function_decl ? DECL_UID (current_function_decl) : -1;
+  entry.var = error_mark_node;
+  source_location_table_entry *entryp
+    = source_location_table->find_slot (entry, INSERT);
+  tree var;
+  if (entryp->var)
+    var = entryp->var;
+  else
+    {
+      char tmp_name[32];
+      ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lsrc_loc", source_location_id++);
+      var = build_decl (loc, VAR_DECL, get_identifier (tmp_name),
+			source_location_impl);
+      TREE_STATIC (var) = 1;
+      TREE_PUBLIC (var) = 0;
+      DECL_ARTIFICIAL (var) = 1;
+      DECL_IGNORED_P (var) = 1;
+      DECL_EXTERNAL (var) = 0;
+      DECL_DECLARED_CONSTEXPR_P (var) = 1;
+      DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (var) = 1;
+      layout_decl (var, 0);
+
+      vec<constructor_elt, va_gc> *v = NULL;
+      vec_alloc (v, 4);
+      for (tree field = TYPE_FIELDS (source_location_impl);
+	   (field = next_initializable_field (field)) != NULL_TREE;
+	   field = DECL_CHAIN (field))
+	{
+	  const char *n = IDENTIFIER_POINTER (DECL_NAME (field));
+	  tree val = NULL_TREE;
+	  if (strcmp (n, "_M_file_name") == 0)
+	    {
+	      if (const char *fname = LOCATION_FILE (loc))
+		{
+		  fname = remap_macro_filename (fname);
+		  val = build_string_literal (strlen (fname) + 1, fname);
+		}
+	      else
+		val = build_string_literal (1, "");
+	    }
+	  else if (strcmp (n, "_M_function_name") == 0)
+	    {
+	      const char *name = "";
+
+	      if (current_function_decl)
+		name = cxx_printable_name (current_function_decl, 0);
+
+	      val = build_string_literal (strlen (name) + 1, name);
+	    }
+	  else if (strcmp (n, "_M_line") == 0)
+	    val = build_int_cst (TREE_TYPE (field), LOCATION_LINE (loc));
+	  else if (strcmp (n, "_M_column") == 0)
+	    val = build_int_cst (TREE_TYPE (field), LOCATION_COLUMN (loc));
+	  else
+	    gcc_unreachable ();
+	  CONSTRUCTOR_APPEND_ELT (v, field, val);
+	}
+
+      tree ctor = build_constructor (source_location_impl, v);
+      TREE_CONSTANT (ctor) = 1;
+      TREE_STATIC (ctor) = 1;
+      DECL_INITIAL (var) = ctor;
+      varpool_node::finalize_decl (var);
+      *entryp = entry;
+      entryp->var = var;
+    }
+
+  return build_fold_addr_expr_with_type_loc (loc, var, const_ptr_type_node);
+}
+
 #include "gt-cp-cp-gimplify.h"
--- gcc/cp/constexpr.c.jj	2019-12-03 20:25:37.155668167 +0100
+++ gcc/cp/constexpr.c	2019-12-03 21:45:31.810989692 +0100
@@ -1240,6 +1240,9 @@ cxx_eval_builtin_function_call (const co
       return boolean_true_node;
     }
 
+  if (fndecl_built_in_p (fun, CP_BUILT_IN_SOURCE_LOCATION, BUILT_IN_FRONTEND))
+    return fold_builtin_source_location (EXPR_LOCATION (t));
+
   /* Be permissive for arguments to built-ins; __builtin_constant_p should
      return constant false for a non-constant argument.  */
   constexpr_ctx new_ctx = *ctx;
--- gcc/cp/tree.c.jj	2019-12-03 20:21:29.728477112 +0100
+++ gcc/cp/tree.c	2019-12-03 21:45:31.811989676 +0100
@@ -445,7 +445,9 @@ builtin_valid_in_constant_expr_p (const_
   if (DECL_BUILT_IN_CLASS (decl) != BUILT_IN_NORMAL)
     {
       if (fndecl_built_in_p (decl, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
-			   BUILT_IN_FRONTEND))
+			     BUILT_IN_FRONTEND)
+	  || fndecl_built_in_p (decl, CP_BUILT_IN_SOURCE_LOCATION,
+				BUILT_IN_FRONTEND))
 	return true;
       /* Not a built-in.  */
       return false;
--- gcc/cp/decl.c.jj	2019-12-03 20:21:29.706477450 +0100
+++ gcc/cp/decl.c	2019-12-03 21:45:31.815989615 +0100
@@ -4290,6 +4290,12 @@ cxx_init_decl_processing (void)
 			    BUILT_IN_FRONTEND, NULL, NULL_TREE);
   set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
 
+  tree cptr_ftype = build_function_type_list (const_ptr_type_node, NULL_TREE);
+  decl = add_builtin_function ("__builtin_source_location",
+			       cptr_ftype, CP_BUILT_IN_SOURCE_LOCATION,
+			       BUILT_IN_FRONTEND, NULL, NULL_TREE);
+  set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF);
+
   integer_two_node = build_int_cst (NULL_TREE, 2);
 
   /* Guess at the initial static decls size.  */
--- gcc/cp/name-lookup.c.jj	2019-11-23 11:01:50.824196001 +0100
+++ gcc/cp/name-lookup.c	2019-12-03 21:45:31.816989600 +0100
@@ -5747,6 +5747,8 @@ get_std_name_hint (const char *name)
     {"shared_lock", "<shared_mutex>", cxx14},
     {"shared_mutex", "<shared_mutex>", cxx17},
     {"shared_timed_mutex", "<shared_mutex>", cxx14},
+    /* <source_location>.  */
+    {"source_location", "<source_location>", cxx2a},
     /* <sstream>.  */
     {"basic_stringbuf", "<sstream>", cxx98},
     {"basic_istringstream", "<sstream>", cxx98},
--- gcc/testsuite/g++.dg/cpp2a/srcloc1.C.jj	2019-12-03 21:45:31.816989600 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc1.C	2019-12-03 21:54:12.200006385 +0100
@@ -0,0 +1,114 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+      const char *_M_file_name;
+      const char *_M_function_name;
+      unsigned int _M_line, _M_column;
+    };
+    const __impl *__ptr;
+    constexpr source_location () : __ptr (nullptr) {}
+    static consteval source_location
+    current (const void *__p = __builtin_source_location ()) {
+      source_location __ret;
+      __ret.__ptr = static_cast <const __impl *> (__p);
+      return __ret;
+    }
+    constexpr const char *file_name () const {
+      return __ptr ? __ptr->_M_file_name : "";
+    }
+    constexpr const char *function_name () const {
+      return __ptr ? __ptr->_M_function_name : "";
+    }
+    constexpr unsigned line () const {
+      return __ptr ? __ptr->_M_line : 0;
+    }
+    constexpr unsigned column () const {
+      return __ptr ? __ptr->_M_column : 0;
+    }
+  };
+}
+
+using namespace std;
+
+consteval source_location
+bar (const source_location x = source_location::current ())
+{
+  return x;
+}
+
+void
+foo (const char **p, unsigned *q)
+{
+  constexpr source_location s = source_location::current ();
+  constexpr source_location t = bar ();
+  p[0] = s.file_name ();
+  p[1] = s.function_name ();
+  q[0] = s.line ();
+  q[1] = s.column ();
+  p[2] = t.file_name ();
+  p[3] = t.function_name ();
+  q[2] = t.line ();
+  q[3] = t.column ();
+  constexpr const char *r = s.file_name ();
+}
+
+source_location s3 = source_location::current ();
+
+template <int N>
+constexpr source_location
+baz ()
+{
+  return source_location::current ();
+}
+
+#define A \
+  source_location s[3] = { source_location::current (), \
+			   source_location::current (), \
+			   source_location::current () }
+
+source_location *
+boo ()
+{
+  static A;
+  return &s[0];
+}
+
+constexpr source_location s1 = baz <0> ();
+constexpr source_location s2 = baz <1> ();
+const source_location *p1 = &s1;
+const source_location *p2 = &s2;
+static_assert (source_location::current ().line () == __LINE__);
+static_assert (source_location::current ().column () == 42);
+
+constexpr bool
+quux ()
+{
+  const char *file1 = source_location::current ().file_name ();
+  const char *file2 = __FILE__;
+  const char *function1 = source_location::current ().function_name ();
+  const char *function2 = __FUNCTION__;
+  int line1 = source_location::current ().line ();
+  int line2 = __LINE__ - 1;
+  int column
+    = source_location::current ().column ();
+  int i = 0;
+  for (; file1[i]; i++)
+    if (file1[i] != file2[i])
+      return false;
+  if (file2[i])
+    return false;
+  for (i = 0; function1[i]; i++)
+    if (function1[i] != function2[i])
+      return false;
+  if (function2[i])
+    return false;
+  if (line1 != line2)
+    return false;
+  if (column != 33)
+    return false;
+  return true;
+}
+
+static_assert (quux ());
--- gcc/testsuite/g++.dg/cpp2a/srcloc2.C.jj	2019-12-03 21:45:31.816989600 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc2.C	2019-12-03 21:54:12.201006370 +0100
@@ -0,0 +1,118 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  inline namespace _8 { }
+  namespace _8 {
+  struct source_location {
+    struct __impl {
+      const char *_M_file_name;
+      const char *_M_function_name;
+      unsigned int _M_line, _M_column;
+    };
+    const __impl *__ptr;
+    constexpr source_location () : __ptr (nullptr) {}
+    static consteval source_location
+    current (const void *__p = __builtin_source_location ()) {
+      source_location __ret;
+      __ret.__ptr = static_cast <const __impl *> (__p);
+      return __ret;
+    }
+    constexpr const char *file_name () const {
+      return __ptr ? __ptr->_M_file_name : "";
+    }
+    constexpr const char *function_name () const {
+      return __ptr ? __ptr->_M_function_name : "";
+    }
+    constexpr unsigned line () const {
+      return __ptr ? __ptr->_M_line : 0;
+    }
+    constexpr unsigned column () const {
+      return __ptr ? __ptr->_M_column : 0;
+    }
+  };
+  }
+}
+
+using namespace std;
+
+consteval source_location
+bar (const source_location x = source_location::current ())
+{
+  return x;
+}
+
+void
+foo (const char **p, unsigned *q)
+{
+  constexpr source_location s = source_location::current ();
+  constexpr source_location t = bar ();
+  p[0] = s.file_name ();
+  p[1] = s.function_name ();
+  q[0] = s.line ();
+  q[1] = s.column ();
+  p[2] = t.file_name ();
+  p[3] = t.function_name ();
+  q[2] = t.line ();
+  q[3] = t.column ();
+  constexpr const char *r = s.file_name ();
+}
+
+source_location s3 = source_location::current ();
+
+template <int N>
+constexpr source_location
+baz ()
+{
+  return source_location::current ();
+}
+
+#define A \
+  source_location s[3] = { source_location::current (), \
+			   source_location::current (), \
+			   source_location::current () }
+
+source_location *
+boo ()
+{
+  static A;
+  return &s[0];
+}
+
+constexpr source_location s1 = baz <0> ();
+constexpr source_location s2 = baz <1> ();
+const source_location *p1 = &s1;
+const source_location *p2 = &s2;
+
+static_assert (source_location::current ().line () == __LINE__);
+static_assert (source_location::current ().column () == 42);
+
+constexpr bool
+quux ()
+{
+  const char *file1 = source_location::current ().file_name ();
+  const char *file2 = __FILE__;
+  const char *function1 = source_location::current ().function_name ();
+  const char *function2 = __FUNCTION__;
+  int line1 = source_location::current ().line ();
+  int line2 = __LINE__ - 1;
+  int column
+    = source_location::current ().column ();
+  int i = 0;
+  for (; file1[i]; i++)
+    if (file1[i] != file2[i])
+      return false;
+  if (file2[i])
+    return false;
+  for (i = 0; function1[i]; i++)
+    if (function1[i] != function2[i])
+      return false;
+  if (function2[i])
+    return false;
+  if (line1 != line2)
+    return false;
+  if (column != 33)
+    return false;
+  return true;
+}
+
+static_assert (quux ());
--- gcc/testsuite/g++.dg/cpp2a/srcloc3.C.jj	2019-12-03 21:45:31.816989600 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc3.C	2019-12-03 21:54:12.201006370 +0100
@@ -0,0 +1,5 @@
+// { dg-do compile { target c++2a } }
+
+auto x = __builtin_source_location ();	// { dg-error "'source_location' is not a member of 'std'" }
+// { dg-message "std::source_location' is defined in header '<source_location>'; did you forget to '#include <source_location>'" "" { target *-*-* } .-1 }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-2 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc4.C.jj	2019-12-03 21:45:31.816989600 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc4.C	2019-12-03 21:54:12.201006370 +0100
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  void source_location ();
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'void std::source_location\\(\\)' is not a type" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc5.C.jj	2019-12-03 21:45:31.816989600 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc5.C	2019-12-03 21:54:12.201006370 +0100
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  typedef int source_location;
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location'\[^\n\r]*is not a class type" }
+// { dg-error "'__impl' is not a member of 'std::source_location'" "" { target *-*-* } .-1 }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-2 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc6.C.jj	2019-12-03 21:45:31.816989600 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc6.C	2019-12-03 21:54:12.201006370 +0100
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'__impl' is not a member of 'std::source_location'" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc7.C.jj	2019-12-03 21:45:31.816989600 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc7.C	2019-12-03 21:54:12.202006355 +0100
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    static void __impl ();
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl\\(\\)' is not a type" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc8.C.jj	2019-12-03 21:45:31.816989600 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc8.C	2019-12-03 21:54:12.202006355 +0100
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    typedef int __impl;
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl()' is not a class type" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc9.C.jj	2019-12-03 21:45:31.816989600 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc9.C	2019-12-03 21:54:12.202006355 +0100
@@ -0,0 +1,11 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+    };
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl' does not contain only non-static data members '_M_file_name', '_M_function_name', '_M_line' and '_M_column'" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc10.C.jj	2019-12-03 21:45:31.817989584 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc10.C	2019-12-03 21:54:12.199006401 +0100
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+      const char *_M_file_name, *_M_function_name;
+      int __foo, _M_line, _M_column;
+    };
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl' does not contain only non-static data members '_M_file_name', '_M_function_name', '_M_line' and '_M_column'" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc11.C.jj	2019-12-03 21:45:31.817989584 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc11.C	2019-12-03 21:54:12.199006401 +0100
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+      const char *_M_file_name, *_M_function_name;
+      int _M_line;
+    };
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl' does not contain only non-static data members '_M_file_name', '_M_function_name', '_M_line' and '_M_column'" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc12.C.jj	2019-12-03 21:45:31.817989584 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc12.C	2019-12-03 21:54:12.199006401 +0100
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+      const void *_M_file_name;
+      const char *_M_function_name;
+      int _M_line, _M_column;
+    };
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl::_M_file_name' does not have 'const char \\*' type" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc13.C.jj	2019-12-03 21:45:31.817989584 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc13.C	2019-12-03 21:54:12.199006401 +0100
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+      const char *_M_file_name;
+      const char *_M_function_name;
+      float _M_line;
+      int _M_column;
+    };
+  };
+}
+
+auto x = __builtin_source_location ();	// { dg-error "'std::source_location::__impl::_M_line' does not have integral type" }
+// { dg-message "evaluating '__builtin_source_location'" "" { target *-*-* } .-1 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc14.C.jj	2019-12-03 21:45:31.817989584 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc14.C	2019-12-03 21:54:12.200006385 +0100
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++2a } }
+
+namespace std {
+  struct source_location {
+    struct __impl {
+      // Test that ordering doesn't matter
+      long long _M_column;
+      const char *_M_file_name;
+      int _M_line;
+      const char *_M_function_name;
+    };
+  };
+}
+
+auto x = __builtin_source_location ();


	Jakub

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2019-12-03 21:02 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-14 20:20 [RFC C++ PATCH] __builtin_source_location () Jakub Jelinek
2019-11-14 22:25 ` Jonathan Wakely
2019-11-14 22:40   ` Jakub Jelinek
2019-11-15 12:35     ` Jonathan Wakely
2019-11-15 12:32 ` [C++ " Jakub Jelinek
2019-11-15 12:38   ` Jonathan Wakely
2019-11-15 12:55     ` Jakub Jelinek
2019-11-15 14:06       ` Jonathan Wakely
2019-11-15 14:05   ` David Malcolm
2019-11-15 14:26     ` Jakub Jelinek
2019-12-03 15:19   ` Patch ping (was Re: [C++ PATCH] __builtin_source_location ()) Jakub Jelinek
2019-12-03 20:37   ` [C++ PATCH] __builtin_source_location () Jason Merrill
2019-12-03 21:02     ` Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).