Hi! While std::source_location::current () is static consteval source_location current() noexcept; in the standard, it also says with LWG3396: "Any call to current that appears as a default member initializer ([class.mem]), or as a subexpression thereof, should correspond to the location of the constructor definition or aggregate initialization that uses the default member initializer. Any call to current that appears as a default argument ([dcl.fct.default]), or as a subexpression thereof, should correspond to the location of the invocation of the function that uses the default argument ([expr.call])." so it must work as compiler magic rather than normal immediate functions, in particular we need to defer its evaluation when parsing default arguments or nsdmis.
The following patch implements that. Bootstrapped/regtested on x86_64-linux and i686-linux. Jon, does it fix all the library testcases you and JeanHeyd had? 2020-12-01 Jakub Jelinek <ja...@redhat.com> LWG3396 Clarify point of reference for source_location::current() PR c++/80780 PR c++/93093 * cp-tree.h (source_location_current_p): Declare. * tree.c (source_location_current_p): New function. (bot_manip): Resolve deferred calls to immediate function std::source_location::current (). * call.c (build_over_call): Don't evaluate calls to immediate function std::source_location::current () in default arguments or when parsing nsdmi. * g++.dg/cpp2a/srcloc15.C: New test. * g++.dg/cpp2a/srcloc16.C: New test. --- gcc/cp/cp-tree.h.jj 2020-11-26 16:22:24.252407018 +0100 +++ gcc/cp/cp-tree.h 2020-11-30 19:45:36.784286305 +0100 @@ -7413,6 +7413,7 @@ extern tree bind_template_template_parm extern tree array_type_nelts_total (tree); extern tree array_type_nelts_top (tree); extern bool array_of_unknown_bound_p (const_tree); +extern bool source_location_current_p (tree); extern tree break_out_target_exprs (tree, bool = false); extern tree build_ctor_subob_ref (tree, tree, tree); extern tree replace_placeholders (tree, tree, bool * = NULL); --- gcc/cp/tree.c.jj 2020-11-26 16:22:24.264406884 +0100 +++ gcc/cp/tree.c 2020-11-30 19:53:58.034686074 +0100 @@ -2968,6 +2968,37 @@ array_type_nelts_total (tree type) return sz; } +/* Return true if FNDECL is std::source_location::current () method. */ + +bool +source_location_current_p (tree fndecl) +{ + gcc_checking_assert (TREE_CODE (fndecl) == FUNCTION_DECL + && DECL_IMMEDIATE_FUNCTION_P (fndecl)); + if (DECL_NAME (fndecl) == NULL_TREE + || TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != RECORD_TYPE + || DECL_CONTEXT (fndecl) != TREE_TYPE (TREE_TYPE (fndecl))) + return false; + + if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "current") != 0) + return false; + + tree source_location = DECL_CONTEXT (fndecl); + if (TYPE_NAME (source_location) == NULL_TREE + || TREE_CODE (TYPE_NAME (source_location)) != TYPE_DECL + || DECL_NAME (TYPE_NAME (source_location)) == NULL_TREE + || strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (source_location))), + "source_location") != 0) + return false; + + tree decl + = lookup_qualified_name (std_node, + DECL_NAME (TYPE_NAME (source_location)), + LOOK_want::TYPE, tf_none); + return TYPE_NAME (source_location) == decl; +} + struct bot_data { splay_tree target_remap; @@ -3064,6 +3095,38 @@ bot_manip (tree* tp, int* walk_subtrees, set_flags_from_callee (*tp); if (data.clear_location && EXPR_HAS_LOCATION (*tp)) SET_EXPR_LOCATION (*tp, input_location); + if (TREE_CODE (*tp) == CALL_EXPR + && !processing_template_decl + && (current_function_decl == NULL_TREE + || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl))) + if (tree fndecl = cp_get_callee_fndecl_nofold (*tp)) + if (DECL_IMMEDIATE_FUNCTION_P (fndecl) + && source_location_current_p (fndecl)) + { + bool ok = call_expr_nargs (*tp) == 0; + if (call_expr_nargs (*tp) == 1 + && TREE_CODE (CALL_EXPR_ARG (*tp, 0)) == CALL_EXPR) + if (tree fndecl2 + = cp_get_callee_fndecl_nofold (CALL_EXPR_ARG (*tp, 0))) + if (fndecl_built_in_p (fndecl2, CP_BUILT_IN_SOURCE_LOCATION, + BUILT_IN_FRONTEND)) + ok = true; + if (!ok) + { + error_at (EXPR_LOCATION (*tp), + "%qD called with arguments", fndecl); + *tp = build_constructor (TREE_TYPE (TREE_TYPE (fndecl)), + NULL); + } + else + { + vec<tree, va_gc> *args = NULL; + push_deferring_access_checks (dk_no_check); + *tp = build_new_function_call (fndecl, &args, + tf_warning_or_error); + pop_deferring_access_checks (); + } + } return t; } --- gcc/cp/call.c.jj 2020-11-18 09:40:09.000000000 +0100 +++ gcc/cp/call.c 2020-11-30 19:47:03.951312431 +0100 @@ -8613,7 +8613,9 @@ build_over_call (struct z_candidate *can && (current_function_decl == NULL_TREE || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)) && (current_binding_level->kind != sk_function_parms - || !current_binding_level->immediate_fn_ctx_p)) + || (!current_binding_level->immediate_fn_ctx_p + && !source_location_current_p (fn))) + && (!parsing_nsdmi () || !source_location_current_p (fn))) { tree obj_arg = NULL_TREE, exprimm = expr; if (DECL_CONSTRUCTOR_P (fn)) @@ -9257,7 +9259,9 @@ build_over_call (struct z_candidate *can && (current_function_decl == NULL_TREE || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)) && (current_binding_level->kind != sk_function_parms - || !current_binding_level->immediate_fn_ctx_p)) + || (!current_binding_level->immediate_fn_ctx_p + && !source_location_current_p (fndecl))) + && (!parsing_nsdmi () || !source_location_current_p (fndecl))) { tree obj_arg = NULL_TREE; if (DECL_CONSTRUCTOR_P (fndecl)) --- gcc/testsuite/g++.dg/cpp2a/srcloc15.C.jj 2020-11-30 17:57:41.506279816 +0100 +++ gcc/testsuite/g++.dg/cpp2a/srcloc15.C 2020-11-30 17:57:21.169507324 +0100 @@ -0,0 +1,82 @@ +// { dg-do compile { target c++20 } } + +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; + +constexpr source_location +foo (const source_location x = source_location::current ()) +{ + return x; +} + +constexpr bool +bar () +{ + int line = __LINE__; + source_location a = foo (); + source_location b = source_location::current (); + source_location c = foo (); + // ^ column 28 + // ^ column 49 + const source_location *d[3] = { &a, &b, &c }; + const char *file1 = __FILE__; + const char *function1 = __FUNCTION__; + for (int j = 0; j < 3; j++) + { + int i= 0; + const char *file2 = d[j]->file_name (); + const char *function2 = d[j]->function_name (); + for (i = 0; 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 (d[j]->line () != line + j + 1) + return false; + if (d[j]->column () != (j == 1 ? 49 : 28)) + return false; + } + return true; +} + +static_assert (bar ()); + +int +main () +{ + bar (); +} --- gcc/testsuite/g++.dg/cpp2a/srcloc16.C.jj 2020-11-30 20:15:25.416283572 +0100 +++ gcc/testsuite/g++.dg/cpp2a/srcloc16.C 2020-11-30 20:15:06.285497601 +0100 @@ -0,0 +1,96 @@ +// { dg-do compile { target c++20 } } + +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; + +struct S +{ + source_location a = source_location::current (); + source_location b = source_location::current (); + source_location c = source_location (); + constexpr S () { c = source_location::current (); } +}; + +struct T +{ + int t; + source_location u = source_location::current (); + int v = __builtin_LINE (); +}; + +constexpr S s; +constexpr T t = { 1 }; + +constexpr bool +cmp (const char *p, const char *q) +{ + for (; *p && *q; p++, q++) + if (*p != *q) + return true; + return *p || *q; +} + +constexpr bool +foo () +{ + T u = { 2 }; + source_location v = source_location::current (); + if (cmp (s.a.file_name (), s.c.file_name ()) + || cmp (s.b.file_name (), s.c.file_name ()) + || cmp (t.u.file_name (), s.c.file_name ()) + || cmp (u.u.file_name (), s.c.file_name ()) + || cmp (v.file_name (), s.c.file_name ()) + || cmp (s.a.function_name (), s.c.function_name ()) + || cmp (s.b.function_name (), s.c.function_name ()) + || cmp (t.u.function_name (), "") + || cmp (u.u.function_name (), v.function_name ()) + || s.a.line () != s.c.line () + || s.b.line () != s.c.line () + || t.u.line () != t.v + || u.u.line () + 1 != v.line () + || s.a.column () != 18 + || s.b.column () != 18 + || s.c.column () != 50 + || t.u.column () != 21 + || u.u.column () != 13 + || v.column () != 49) + return false; + return true; +} + +static_assert (foo ()); + +int +main () +{ + foo (); +} Jakub