static GTY(()) hash_table <source_location_table_entry_hash>
*source_location_table;
-static GTY(()) unsigned int source_location_id;
/* Fold the __builtin_source_location () call T. */
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),
+ var = build_decl (loc, VAR_DECL, generate_internal_label ("Lsrc_loc"),
source_location_impl);
TREE_STATIC (var) = 1;
TREE_PUBLIC (var) = 0;
tt_decl, /* By-value mergeable decl. */
tt_tpl_parm, /* Template parm. */
- /* The ordering of the following 4 is relied upon in
+ /* The ordering of the following 5 is relied upon in
trees_out::tree_node. */
tt_id, /* Identifier node. */
tt_conv_id, /* Conversion operator name. */
tt_anon_id, /* Anonymous name. */
tt_lambda_id, /* Lambda name. */
+ tt_internal_id, /* Internal name. */
tt_typedef_type, /* A (possibly implicit) typedefed type. */
tt_derived_type, /* A type derived from another type. */
&& (TREE_CODE (t) != TYPE_DECL
|| (DECL_ARTIFICIAL (t) && !DECL_CONTEXT (t)))
&& (TREE_CODE (t) != VAR_DECL
- || (!DECL_NAME (t) && !DECL_CONTEXT (t)))
+ || ((!DECL_NAME (t)
+ || IDENTIFIER_INTERNAL_P (DECL_NAME (t)))
+ && !DECL_CONTEXT (t)))
&& TREE_CODE (t) != FUNCTION_DECL));
if (streaming_p ())
&& dump ("Written type:%d %C:%N", type_tag, TREE_CODE (type), type);
}
+ /* For uncontexted VAR_DECLs we need to stream the definition so that
+ importers can recreate their value. */
+ if (TREE_CODE (t) == VAR_DECL)
+ {
+ gcc_checking_assert (!DECL_NONTRIVIALLY_INITIALIZED_P (t));
+ tree_node (DECL_INITIAL (t));
+ }
+
if (streaming_p ())
dump (dumper::TREE) && dump ("Written tree:%d %C:%N", tag, TREE_CODE (t), t);
}
&& dump ("Read type:%d %C:%N", type_tag, TREE_CODE (type), type);
}
+ if (TREE_CODE (t) == VAR_DECL)
+ {
+ DECL_INITIAL (t) = tree_node ();
+ if (TREE_STATIC (t))
+ varpool_node::finalize_decl (t);
+ }
+
if (TREE_CODE (t) == LAMBDA_EXPR
&& CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (t)))
{
if (TREE_CODE (t) == IDENTIFIER_NODE)
{
- /* An identifier node -> tt_id, tt_conv_id, tt_anon_id, tt_lambda_id. */
+ /* An identifier node -> tt_id, tt_conv_id, tt_anon_id, tt_lambda_id,
+ tt_internal_id. */
int code = tt_id;
if (IDENTIFIER_ANON_P (t))
code = IDENTIFIER_LAMBDA_P (t) ? tt_lambda_id : tt_anon_id;
+ else if (IDENTIFIER_INTERNAL_P (t))
+ code = tt_internal_id;
else if (IDENTIFIER_CONV_OP_P (t))
code = tt_conv_id;
}
else if (code == tt_id && streaming_p ())
str (IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t));
+ else if (code == tt_internal_id && streaming_p ())
+ str (prefix_for_internal_label (t));
int tag = insert (t);
if (streaming_p ())
{
- /* We know the ordering of the 4 id tags. */
+ /* We know the ordering of the 5 id tags. */
static const char *const kinds[] =
- {"", "conv_op ", "anon ", "lambda "};
+ {"", "conv_op ", "anon ", "lambda ", "internal "};
dump (dumper::TREE)
&& dump ("Written:%d %sidentifier:%N", tag,
kinds[code - tt_id],
break;
case VAR_DECL:
- /* AGGR_INIT_EXPRs cons up anonymous uncontexted VAR_DECLs. */
- gcc_checking_assert (!DECL_NAME (t)
+ /* AGGR_INIT_EXPRs cons up anonymous uncontexted VAR_DECLs,
+ and internal vars are created by sanitizers and
+ __builtin_source_location. */
+ gcc_checking_assert ((!DECL_NAME (t)
+ || IDENTIFIER_INTERNAL_P (DECL_NAME (t)))
&& DECL_ARTIFICIAL (t));
break;
}
break;
+ case tt_internal_id:
+ /* An internal label. */
+ {
+ const char *prefix = str ();
+ res = generate_internal_label (prefix);
+ int tag = insert (res);
+ dump (dumper::TREE)
+ && dump ("Read internal identifier:%d %N", tag, res);
+ }
+ break;
+
case tt_typedef_type:
res = tree_node ();
if (res)
--- /dev/null
+// PR c++/118904
+
+#include <source_location>
+inline std::source_location foo() {
+ return std::source_location::current();
+}
--- /dev/null
+// PR c++/118904
+// { dg-additional-options "-fmodule-header -std=c++20 -fdump-lang-module-uid" }
+// { dg-module-cmi {} }
+
+#include "src-loc-1.h"
+
+// { dg-final { scan-lang-dump {Written:-[0-9]* internal identifier:[^\n\r]*Lsrc_loc} module } }
--- /dev/null
+// PR c++/118904
+// { dg-additional-options "-fmodules -std=c++20 -fno-module-lazy" }
+
+#include "src-loc-1.h"
+import "src-loc-1_a.H";
--- /dev/null
+// PR c++/118904
+// { dg-module-do run }
+// { dg-additional-options "-fmodules -std=c++20 -fdump-lang-module-uid" }
+
+import "src-loc-1_a.H";
+
+int main() {
+ const char* a = foo().function_name();
+ const char* b = std::source_location::current().function_name();
+ if (__builtin_strcmp(a, "std::source_location foo()"))
+ __builtin_abort();
+ if (__builtin_strcmp(b, "int main()"))
+ __builtin_abort();
+}
+
+// { dg-final { scan-lang-dump {Read internal identifier:-[0-9]* [^\n\r]*Lsrc_loc} module } }
--- /dev/null
+// PR c++/98735
+// { dg-additional-options "-fmodules -fsanitize=undefined -Wno-return-type" }
+// { dg-module-cmi X }
+
+export module X;
+
+export inline int f(int x) {
+ if (x > 0)
+ return x * 5;
+}
--- /dev/null
+// PR c++/98735
+// { dg-additional-options "-fmodules -fsanitize=undefined -Wno-return-type" }
+// Note: can't work out how to do a link test here.
+
+int g(int x) {
+ if (x > 0)
+ return x - 5;
+}
+
+import X;
+
+int main() {
+ f(123);
+}
--- /dev/null
+// PR c++/98735
+
+int g(int x) {
+ if (x > 0)
+ return x - 5;
+}
+
+import X;
+
+int main() {
+ f(123);
+}
--- /dev/null
+// PR c++/98735
+// { dg-do run { target c++17 } }
+// { dg-options "-fmodules -fsanitize=undefined -Wno-return-type" }
+// { dg-additional-sources module-1-aux.cc }
+
+export module X;
+
+export inline int f(int x) {
+ if (x > 0)
+ return x * 5;
+}
}
\f
+/* Mapping from prefix to label number. */
+
+struct identifier_hash : ggc_ptr_hash <tree_node>
+{
+ static inline hashval_t hash (tree t)
+ {
+ return IDENTIFIER_HASH_VALUE (t);
+ }
+};
+struct identifier_count_traits
+ : simple_hashmap_traits<identifier_hash, long> {};
+typedef hash_map<tree, long, identifier_count_traits> internal_label_map;
+static GTY(()) internal_label_map *internal_label_nums;
+
+/* Generates an identifier intended to be used internally with the
+ given PREFIX. This is intended to be used by the frontend so that
+ C++ modules can regenerate appropriate (non-clashing) identifiers on
+ stream-in. */
+
+tree
+generate_internal_label (const char *prefix)
+{
+ tree prefix_id = get_identifier (prefix);
+ if (!internal_label_nums)
+ internal_label_nums = internal_label_map::create_ggc();
+ long &num = internal_label_nums->get_or_insert (prefix_id);
+
+ char tmp[32];
+ ASM_GENERATE_INTERNAL_LABEL (tmp, prefix, num++);
+
+ tree id = get_identifier (tmp);
+ IDENTIFIER_INTERNAL_P (id) = true;
+
+ /* Cache the prefix on the identifier so we can retrieve it later. */
+ TREE_CHAIN (id) = prefix_id;
+
+ return id;
+}
+
+/* Get the PREFIX we created the internal identifier LABEL with. */
+
+const char *
+prefix_for_internal_label (tree label)
+{
+ gcc_assert (IDENTIFIER_INTERNAL_P (label)
+ && !IDENTIFIER_TRANSPARENT_ALIAS (label)
+ && TREE_CHAIN (label)
+ && TREE_CODE (TREE_CHAIN (label)) == IDENTIFIER_NODE);
+ return IDENTIFIER_POINTER (TREE_CHAIN (label));
+}
+
/* The name of the object as the assembler will see it (but before any
translations made by ASM_OUTPUT_LABELREF). Often this is the same
as DECL_NAME. It is an IDENTIFIER_NODE. */
#define IDENTIFIER_ANON_P(NODE) \
(IDENTIFIER_NODE_CHECK (NODE)->base.private_flag)
+/* Nonzero indicates an IDENTIFIER_NODE that names an internal label.
+ The prefix used to generate the label can be found on the TREE_CHAIN. */
+#define IDENTIFIER_INTERNAL_P(NODE) \
+ (IDENTIFIER_NODE_CHECK (NODE)->base.volatile_flag)
+
/* Nonzero in an IDENTIFIER_NODE if the name is a local alias, whose
uses are to be substituted for uses of the TREE_CHAINed identifier. */
#define IDENTIFIER_TRANSPARENT_ALIAS(NODE) \
return VECTOR_CST_NPATTERNS (t) * VECTOR_CST_NELTS_PER_PATTERN (t);
}
+extern tree generate_internal_label (const char *);
+extern const char *prefix_for_internal_label (tree label);
extern tree decl_assembler_name (tree);
extern void overwrite_decl_assembler_name (tree decl, tree name);
extern tree decl_comdat_group (const_tree);
return 0;
}
-/* Counters for internal labels. ubsan_ids[0] for Lubsan_type,
- ubsan_ids[1] for Lubsan_data labels. */
-static GTY(()) unsigned int ubsan_ids[2];
-
/* Helper routine that returns ADDR_EXPR of a VAR_DECL of a type
descriptor. It first looks into the hash table; if not found,
create the VAR_DECL, put it into the hash table and return the
TREE_READONLY (str) = 1;
TREE_STATIC (str) = 1;
- char tmp_name[32];
- ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_type", ubsan_ids[0]++);
- decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
- dtype);
+ decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ generate_internal_label ("Lubsan_type"), dtype);
TREE_STATIC (decl) = 1;
TREE_PUBLIC (decl) = 0;
DECL_ARTIFICIAL (decl) = 1;
layout_type (ret);
/* Now, fill in the type. */
- char tmp_name[32];
- ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_data", ubsan_ids[1]++);
- tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
- ret);
+ tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ generate_internal_label ("Lubsan_data"), ret);
TREE_STATIC (var) = 1;
TREE_PUBLIC (var) = 0;
DECL_ARTIFICIAL (var) = 1;