instance, clobber);
}
+/* Return true if a call to FN with number of arguments NARGS
+ is an immediate invocation. */
+
+static bool
+immediate_invocation_p (tree fn, int nargs)
+{
+ return (TREE_CODE (fn) == FUNCTION_DECL
+ && DECL_IMMEDIATE_FUNCTION_P (fn)
+ && cp_unevaluated_operand == 0
+ && (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)
+ /* As an exception, we defer std::source_location::current ()
+ invocations until genericization because LWG3396 mandates
+ special behavior for it. */
+ && (nargs > 1 || !source_location_current_p (fn)));
+}
+
/* Subroutine of the various build_*_call functions. Overload resolution
has chosen a winning candidate CAND; build up a CALL_EXPR accordingly.
ARGS is a TREE_LIST of the unconverted arguments to the call. FLAGS is a
addr, nargs, argarray);
if (TREE_THIS_VOLATILE (fn) && cfun)
current_function_returns_abnormally = 1;
- if (TREE_CODE (fn) == FUNCTION_DECL
- && DECL_IMMEDIATE_FUNCTION_P (fn)
- && cp_unevaluated_operand == 0
- && (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))
+ if (immediate_invocation_p (fn, nargs))
{
tree obj_arg = NULL_TREE, exprimm = expr;
if (DECL_CONSTRUCTOR_P (fn))
if (TREE_CODE (fn) == ADDR_EXPR)
{
tree fndecl = STRIP_TEMPLATE (TREE_OPERAND (fn, 0));
- if (TREE_CODE (fndecl) == FUNCTION_DECL
- && DECL_IMMEDIATE_FUNCTION_P (fndecl)
- && cp_unevaluated_operand == 0
- && (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))
+ if (immediate_invocation_p (fndecl, nargs))
{
tree obj_arg = NULL_TREE;
if (DECL_CONSTRUCTOR_P (fndecl))
}
if (fndecl_built_in_p (fun, CP_BUILT_IN_SOURCE_LOCATION, BUILT_IN_FRONTEND))
- return fold_builtin_source_location (EXPR_LOCATION (t));
+ {
+ temp_override<tree> ovr (current_function_decl);
+ if (ctx->call && ctx->call->fundef)
+ current_function_decl = ctx->call->fundef->decl;
+ return fold_builtin_source_location (EXPR_LOCATION (t));
+ }
int strops = 0;
int strret = 0;
break;
}
+ if (tree fndecl = cp_get_callee_fndecl (stmt))
+ if (DECL_IMMEDIATE_FUNCTION_P (fndecl))
+ {
+ gcc_assert (source_location_current_p (fndecl));
+ *stmt_p = cxx_constant_value (stmt);
+ break;
+ }
+
if (!wtd->no_sanitize_p
&& sanitize_flags_p ((SANITIZE_NULL
| SANITIZE_ALIGNMENT | SANITIZE_VPTR)))
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);
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))
+ || !id_equal (DECL_NAME (fndecl), "current"))
+ return false;
+
+ tree source_location = DECL_CONTEXT (fndecl);
+ if (TYPE_NAME (source_location) == NULL_TREE
+ || TREE_CODE (TYPE_NAME (source_location)) != TYPE_DECL
+ || TYPE_IDENTIFIER (source_location) == NULL_TREE
+ || !id_equal (TYPE_IDENTIFIER (source_location),
+ "source_location")
+ || !decl_in_std_namespace_p (TYPE_NAME (source_location)))
+ return false;
+
+ return true;
+}
+
struct bot_data
{
splay_tree target_remap;
--- /dev/null
+// { 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 ();
+}
--- /dev/null
+// { 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 ();
+}
--- /dev/null
+// { 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 ();
+}
--- /dev/null
+// { 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 ();
+}