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

Reply via email to