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 <ja...@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