On Tue, Dec 01, 2020 at 04:05:22PM -0500, Jason Merrill via Gcc-patches wrote: > Or simpler might be to always defer immediate evaluation of > source_location::current() until genericize time.
That works. I had to change constexpr.c too so that it temporarily adjusts current_function_decl from the constexpr evaluation context, but we do the same already from __builtin_FUNCTION (). Tested on x86_64-linux and i686-linux, ok for trunk if it passes full bootstrap/regtest? For the non-std::source_location::current() immediate evaluation, I'll just file a PR and put there all details. 2020-12-02 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. * call.c (build_over_call): Don't evaluate calls to immediate function std::source_location::current (). * constexpr.c (cxx_eval_builtin_function_call): Temporarily set current_function_decl from ctx->call->fundef->decl if any. * cp-gimplify.c (cp_genericize_r) <case CALL_EXPR>: Fold calls to immediate function std::source_location::current (). * g++.dg/cpp2a/srcloc15.C: New test. * g++.dg/cpp2a/srcloc16.C: New test. * g++.dg/cpp2a/srcloc17.C: New test. * g++.dg/cpp2a/srcloc18.C: New test. --- gcc/cp/cp-tree.h.jj 2020-12-01 16:13:01.716818440 +0100 +++ gcc/cp/cp-tree.h 2020-12-02 11:49:25.984376796 +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-12-01 16:13:01.717818429 +0100 +++ gcc/cp/tree.c 2020-12-02 11:53:19.032696933 +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; --- gcc/cp/call.c.jj 2020-12-01 16:13:01.714818462 +0100 +++ gcc/cp/call.c 2020-12-02 12:25:25.379566607 +0100 @@ -8613,7 +8613,8 @@ 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) + && (nargs > 1 || !source_location_current_p (fn))) { tree obj_arg = NULL_TREE, exprimm = expr; if (DECL_CONSTRUCTOR_P (fn)) @@ -9257,7 +9258,8 @@ 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) + && (nargs > 1 || !source_location_current_p (fndecl))) { tree obj_arg = NULL_TREE; if (DECL_CONSTRUCTOR_P (fndecl)) --- gcc/cp/constexpr.c.jj 2020-11-26 16:22:24.250407040 +0100 +++ gcc/cp/constexpr.c 2020-12-02 12:35:11.458852298 +0100 @@ -1332,7 +1332,14 @@ cxx_eval_builtin_function_call (const co } if (fndecl_built_in_p (fun, CP_BUILT_IN_SOURCE_LOCATION, BUILT_IN_FRONTEND)) - return fold_builtin_source_location (EXPR_LOCATION (t)); + { + tree save_cur_fn = current_function_decl; + if (ctx->call && ctx->call->fundef) + current_function_decl = ctx->call->fundef->decl; + t = fold_builtin_source_location (EXPR_LOCATION (t)); + current_function_decl = save_cur_fn; + return t; + } int strops = 0; int strret = 0; --- gcc/cp/cp-gimplify.c.jj 2020-11-26 16:22:24.250407040 +0100 +++ gcc/cp/cp-gimplify.c 2020-12-02 12:26:21.596922205 +0100 @@ -1374,6 +1374,15 @@ cp_genericize_r (tree *stmt_p, int *walk break; } + if (call_expr_nargs (stmt) == 0) + if (tree fndecl = cp_get_callee_fndecl (stmt)) + if (DECL_IMMEDIATE_FUNCTION_P (fndecl) + && source_location_current_p (fndecl)) + { + *stmt_p = cxx_constant_value (stmt, NULL_TREE); + break; + } + if (!wtd->no_sanitize_p && sanitize_flags_p ((SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_VPTR))) --- gcc/testsuite/g++.dg/cpp2a/srcloc15.C.jj 2020-12-02 11:49:25.987376761 +0100 +++ gcc/testsuite/g++.dg/cpp2a/srcloc15.C 2020-12-02 12:48:20.592828477 +0100 @@ -0,0 +1,119 @@ +// { dg-do run { 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; +} + +struct S { + const char *func; + unsigned line = 0; + source_location loc = source_location::current (); + + constexpr S (int l, source_location loc = source_location::current ()) + : func(__FUNCTION__), line(l), loc(loc) + {} + + constexpr S (double) + : func(__FUNCTION__), line(__LINE__) + // ^ column 38 + {} +}; + +constexpr bool +cmp (const char *p, const char *q) +{ + for (; *p && *q; p++, q++) + if (*p != *q) + return true; + return *p || *q; +} + +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; + if (cmp (d[j]->file_name (), file1)) + return false; + if (cmp (d[j]->function_name (), function1)) + return false; + if (d[j]->line () != line + j + 1) + return false; + if (d[j]->column () != (j == 1 ? 49 : 28)) + return false; + } + + S e = __LINE__; + // ^ column 9 + S f = 1.0; + if (cmp (e.loc.file_name (), file1)) + return false; + if (cmp (f.loc.file_name (), file1)) + return false; + if (cmp (e.loc.function_name (), function1)) + return false; + if (cmp (f.loc.function_name (), f.func)) + return false; + if (e.loc.line () != e.line) + return false; + if (f.loc.line () != f.line) + return false; + if (e.loc.column () != 9) + return false; + if (f.loc.column () != 38) + return false; + return true; +} + +static_assert (bar ()); + +int +main () +{ + if (!bar ()) + __builtin_abort (); +} --- gcc/testsuite/g++.dg/cpp2a/srcloc16.C.jj 2020-12-02 11:49:25.987376761 +0100 +++ gcc/testsuite/g++.dg/cpp2a/srcloc16.C 2020-12-02 12:27:30.649130680 +0100 @@ -0,0 +1,97 @@ +// { dg-do run { 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 () +{ + if (!foo ()) + __builtin_abort (); +} --- gcc/testsuite/g++.dg/cpp2a/srcloc17.C.jj 2020-12-02 12:50:12.956543583 +0100 +++ gcc/testsuite/g++.dg/cpp2a/srcloc17.C 2020-12-02 12:58:26.113904280 +0100 @@ -0,0 +1,122 @@ +// { dg-do run { 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; + +template <int N> +constexpr source_location +foo (const source_location x = source_location::current ()) +{ + return x; +} + +template <int N> +struct S { + const char *func; + unsigned line = 0; + source_location loc = source_location::current (); + + constexpr S (int l, source_location loc = source_location::current ()) + : func(__FUNCTION__), line(l), loc(loc) + {} + + constexpr S (double) + : func(__FUNCTION__), line(__LINE__) + // ^ column 38 + {} +}; + +constexpr bool +cmp (const char *p, const char *q) +{ + for (; *p && *q; p++, q++) + if (*p != *q) + return true; + return *p || *q; +} + +template <int N> +constexpr bool +bar () +{ + int line = __LINE__; + source_location a = foo<N> (); + source_location b = source_location::current (); + source_location c = foo<N> (); + // ^ column 30 + // ^ column 48 + const source_location *d[3] = { &a, &b, &c }; + const char *file1 = __FILE__; + const char *function1 = b.function_name (); + for (int j = 0; j < 3; j++) + { + int i= 0; + if (cmp (d[j]->file_name (), file1)) + return false; + if (cmp (d[j]->function_name (), function1)) + return false; + if (d[j]->line () != line + j + 1) + return false; + if (d[j]->column () != (j == 1 ? 48 : 30)) + return false; + } + + S<N> e = __LINE__; + // ^ column 8 + S<N> f = 1.0; + if (cmp (e.loc.file_name (), file1)) + return false; + if (cmp (f.loc.file_name (), file1)) + return false; + if (cmp (e.loc.function_name (), function1)) + return false; + if (cmp (f.loc.function_name (), f.func)) + return false; + if (e.loc.line () != e.line) + return false; + if (f.loc.line () != f.line) + return false; + if (e.loc.column () != 8) + return false; + if (f.loc.column () != 38) + return false; + return true; +} + +static_assert (bar<0> ()); + +int +main () +{ + if (!bar<0> ()) + __builtin_abort (); +} --- gcc/testsuite/g++.dg/cpp2a/srcloc18.C.jj 2020-12-02 12:52:10.990193861 +0100 +++ gcc/testsuite/g++.dg/cpp2a/srcloc18.C 2020-12-02 13:01:26.128844951 +0100 @@ -0,0 +1,100 @@ +// { dg-do run { 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; + +template <int N> +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 (); } +}; + +template <int N> +struct T +{ + int t; + source_location u = source_location::current (); + int v = __builtin_LINE (); +}; + +constexpr S<0> s; +constexpr T<0> t = { 1 }; + +constexpr bool +cmp (const char *p, const char *q) +{ + for (; *p && *q; p++, q++) + if (*p != *q) + return true; + return *p || *q; +} + +template <int N> +constexpr bool +foo () +{ + T<N> 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 () != 49 + || t.u.column () != 24 + || u.u.column () != 8 + || v.column () != 48) + return false; + return true; +} + +static_assert (foo<1> ()); + +int +main () +{ + if (!foo<1> ()) + __builtin_abort (); +} Jakub