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