public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093]
@ 2020-12-01  8:59 Jakub Jelinek
  2020-12-01 13:03 ` Jonathan Wakely
  2020-12-01 21:05 ` [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093] Jason Merrill
  0 siblings, 2 replies; 13+ messages in thread
From: Jakub Jelinek @ 2020-12-01  8:59 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely; +Cc: gcc-patches

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  <jakub@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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093]
  2020-12-01  8:59 [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093] Jakub Jelinek
@ 2020-12-01 13:03 ` Jonathan Wakely
  2020-12-01 15:00   ` Jakub Jelinek
  2020-12-02 12:30   ` [PATCH] c++: Change __builtin_source_location to use __PRETTY_FUNCTION__ instead of __FUNCTION__ [PR80780] Jakub Jelinek
  2020-12-01 21:05 ` [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093] Jason Merrill
  1 sibling, 2 replies; 13+ messages in thread
From: Jonathan Wakely @ 2020-12-01 13:03 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, gcc-patches

On 01/12/20 09:59 +0100, Jakub Jelinek wrote:
>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.

Nice.

>Bootstrapped/regtested on x86_64-linux and i686-linux.
>
>Jon, does it fix all the library testcases you and JeanHeyd had?

Most of them pass now, but this case fails:

using namespace std;

struct S {
   const char* func;
   unsigned line = 0;
   source_location loc = source_location::current();

   S(int l, source_location loc = source_location::current())
   : func(__FUNCTION__), line(l), loc(loc) // values of loc will be from call-site
   {}

   S(void*)
   : func(__FUNCTION__), line(__LINE__) // values of loc should be hereabouts
   {}
};

int main()
{
   S s0(__LINE__);
   assert( s0.loc.line() == s0.line );
   assert( !__builtin_strcmp(s0.loc.file_name(), __FILE__) );
   assert( !__builtin_strcmp(s0.loc.function_name(), __FUNCTION__) );
}

The location is the constructor parameter list, but it should be in
main() where the default argument is evaluated.

JeanHeyd's test also verify that the function_name() for the NSDMI
cases is "s::s" but that fails because __FUNCTION__ is only "s".

I mentioned in PR 80780 that a __builtin__PRETTY_FUNCTION would have
been nice, because __FUNCTION__ isn't very useful for C++, because of
overloading and namespace/class scopes. There are an unlimited number
of functions that have __FUNCTION__ == "s", e.g. "ns::s(int)" and
"ns::s()" and "another_scope::s::s<T...>(T...)" etc.

Since __builtin_source_location() can do whatever it wants (without
needing to add __builtin__PRETTY_FUNCTION) it might be nice to use the
__PRETTY_FUNCTION__ string. JeanHeyd's tests would still need changes,
because the name would be "s::s(void*)" not "s::s" but that still
seems better for users.



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093]
  2020-12-01 13:03 ` Jonathan Wakely
@ 2020-12-01 15:00   ` Jakub Jelinek
  2020-12-02 12:30   ` [PATCH] c++: Change __builtin_source_location to use __PRETTY_FUNCTION__ instead of __FUNCTION__ [PR80780] Jakub Jelinek
  1 sibling, 0 replies; 13+ messages in thread
From: Jakub Jelinek @ 2020-12-01 15:00 UTC (permalink / raw)
  To: Jonathan Wakely, Jason Merrill; +Cc: gcc-patches

On Tue, Dec 01, 2020 at 01:03:52PM +0000, Jonathan Wakely wrote:
> Most of them pass now, but this case fails:
> 
> using namespace std;
> 
> struct S {
>   const char* func;
>   unsigned line = 0;
>   source_location loc = source_location::current();
> 
>   S(int l, source_location loc = source_location::current())
>   : func(__FUNCTION__), line(l), loc(loc) // values of loc will be from call-site
>   {}
> 
>   S(void*)
>   : func(__FUNCTION__), line(__LINE__) // values of loc should be hereabouts
>   {}
> };
> 
> int main()
> {
>   S s0(__LINE__);
>// ...
> }

Ah, I see what is going on here.

using namespace std;

struct S {
  const char *func;
  unsigned line = 0;
  source_location loc = source_location::current ();

  S (int l, source_location);

  S (void *)
  : func(__FUNCTION__), line(__LINE__) // values of loc should be hereabouts
  {}
};

S::S (int l, source_location loc = source_location::current ())
: func(__FUNCTION__), line(l), loc(loc) // values of loc will be from call-site
{}

int
main ()
{
  S s0(__LINE__);
///...
}

would work fine.

We have (since this patch, but before that it was already mostly like that
too):
          && 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
                  && !source_location_current_p (fndecl)))
          && (!parsing_nsdmi () || !source_location_current_p (fndecl)))
as the condition whether to evaluate an immediate function right away or
not.
The intent is do not evaluate it in default arguments of immediate functions
(will be done at constant expression evaluation time instead), and (newly)
for std::source_location::current () not evaluated in nsdmis and in default
arguments.

The problem is that with your/JeanHeyd's testcase above, the default
argument parsing is deferred until the whole class is parsed and then
cp_parser_late_parsing_default_args performs that deferred parsing.
Except at this point nothing creates the sk_function_params scope.

So, I think we need some way for the build_over_call code to know if
it is called from within cp_parser_late_parsing_default_args and whether
for an immediate function or not, and take that into account too.

I see cp_parser_late_parsing_default_args calls push_defarg_context,
so perhaps it could check default_arg_context vector, except that
convert_default_arg calls that too around calling break_out_target_exprs
which in the patch is used to perform the late evaluation of the
std::source_location::current() calls.  So it might need to temporarily
pop_defarg_context before break_out_target_exprs and push it again?

Jason, any thoughts on that?

And guess we need some tests if it works as expected also in templates;
I bet we create scope for the default params in that case, but I could be
wrong.

Thanks

	Jakub


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093]
  2020-12-01  8:59 [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093] Jakub Jelinek
  2020-12-01 13:03 ` Jonathan Wakely
@ 2020-12-01 21:05 ` Jason Merrill
  2020-12-01 21:21   ` Jakub Jelinek
  2020-12-02 12:13   ` [PATCH] c++, v2: " Jakub Jelinek
  1 sibling, 2 replies; 13+ messages in thread
From: Jason Merrill @ 2020-12-01 21:05 UTC (permalink / raw)
  To: Jakub Jelinek, Jonathan Wakely; +Cc: gcc-patches

On 12/1/20 3:59 AM, Jakub Jelinek wrote:
> 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 problem is that with your/JeanHeyd's testcase above, the default
> argument parsing is deferred until the whole class is parsed and then
> cp_parser_late_parsing_default_args performs that deferred parsing.
> Except at this point nothing creates the sk_function_params scope.
> 
> So, I think we need some way for the build_over_call code to know if
> it is called from within cp_parser_late_parsing_default_args and whether
> for an immediate function or not, and take that into account too.
> 
> I see cp_parser_late_parsing_default_args calls push_defarg_context,
> so perhaps it could check default_arg_context vector, except that
> convert_default_arg calls that too around calling break_out_target_exprs
> which in the patch is used to perform the late evaluation of the
> std::source_location::current() calls.  So it might need to temporarily
> pop_defarg_context before break_out_target_exprs and push it again?

How about forcing the constant evaluation in bot_manip?

Or simpler might be to always defer immediate evaluation of 
source_location::current() until genericize time.

> And guess we need some tests if it works as expected also in templates;

Please.

> 2020-12-01  Jakub Jelinek  <jakub@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)

You can use id_equal for comparing identifiers to strings.

> +    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)

TYPE_IDENTIFIER would make this shorter.

> +    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;

Why not TYPE_CONTEXT (source_location) == std_node?  I don't think we 
need to do name lookup here.

> +}
> +
>   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))

Please factor this condition out into a separate function.

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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093]
  2020-12-01 21:05 ` [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093] Jason Merrill
@ 2020-12-01 21:21   ` Jakub Jelinek
  2020-12-02 12:13   ` [PATCH] c++, v2: " Jakub Jelinek
  1 sibling, 0 replies; 13+ messages in thread
From: Jakub Jelinek @ 2020-12-01 21:21 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, gcc-patches

On Tue, Dec 01, 2020 at 04:05:22PM -0500, Jason Merrill wrote:
> > I see cp_parser_late_parsing_default_args calls push_defarg_context,
> > so perhaps it could check default_arg_context vector, except that
> > convert_default_arg calls that too around calling break_out_target_exprs
> > which in the patch is used to perform the late evaluation of the
> > std::source_location::current() calls.  So it might need to temporarily
> > pop_defarg_context before break_out_target_exprs and push it again?
> 
> How about forcing the constant evaluation in bot_manip?

That is probably a good idea anyway.

> Or simpler might be to always defer immediate evaluation of
> source_location::current() until genericize time.

Will try this too.

Though, I still wonder if it will be ok that we'll evaluate immediate
functions other than std::source_location::current() during the late
parsing of default arguments.

Testcase could be something like:
consteval bool foo (bool x) { if (x) throw 1; return false; }
consteval bool bar (bool x = foo (true)) { return true; }
struct S
{
  consteval static bool baz (bool x = foo (true)) { return true; }
};
constexpr bool a = bar (true);
constexpr bool b = S::baz (true);

We accept now bar, but reject baz.
I think the foo (true) expressions are in both cases in
immediate function context and therefore foo (true) calls are there
not immediate invocations (sure, if one calls bar () or S::baz () 
then it will be invalid anyway).

	Jakub


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH] c++, v2: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093]
  2020-12-01 21:05 ` [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093] Jason Merrill
  2020-12-01 21:21   ` Jakub Jelinek
@ 2020-12-02 12:13   ` Jakub Jelinek
  2020-12-02 15:19     ` Marek Polacek
  2020-12-02 15:42     ` Jason Merrill
  1 sibling, 2 replies; 13+ messages in thread
From: Jakub Jelinek @ 2020-12-02 12:13 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, gcc-patches

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  <jakub@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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH] c++: Change __builtin_source_location to use __PRETTY_FUNCTION__ instead of __FUNCTION__ [PR80780]
  2020-12-01 13:03 ` Jonathan Wakely
  2020-12-01 15:00   ` Jakub Jelinek
@ 2020-12-02 12:30   ` Jakub Jelinek
  2020-12-02 20:18     ` Jason Merrill
  1 sibling, 1 reply; 13+ messages in thread
From: Jakub Jelinek @ 2020-12-02 12:30 UTC (permalink / raw)
  To: Jason Merrill, Jonathan Wakely; +Cc: gcc-patches

Hi!

On Tue, Dec 01, 2020 at 01:03:52PM +0000, Jonathan Wakely via Gcc-patches wrote:
> I mentioned in PR 80780 that a __builtin__PRETTY_FUNCTION would have
> been nice, because __FUNCTION__ isn't very useful for C++, because of
> overloading and namespace/class scopes. There are an unlimited number
> of functions that have __FUNCTION__ == "s", e.g. "ns::s(int)" and
> "ns::s()" and "another_scope::s::s<T...>(T...)" etc.
> 
> Since __builtin_source_location() can do whatever it wants (without
> needing to add __builtin__PRETTY_FUNCTION) it might be nice to use the
> __PRETTY_FUNCTION__ string. JeanHeyd's tests would still need changes,
> because the name would be "s::s(void*)" not "s::s" but that still
> seems better for users.

When I've added template tests for the previous patch, I have noticed that
the current __builtin_source_location behavior is not really __FUNCTION__,
just close, because e.g. in function template __FUNCTION__ is still
"bar" but __builtin_source_location gave "bar<0>".

Anyway, this patch implements above request to follow __PRETTY_FUNCTION__
(on top of the earlier posted patch).

Tested on x86_64-linux, ok for trunk if it passes full bootstrap/regtest on
x86_64-linux?

2020-12-02  Jakub Jelinek  <jakub@redhat.com>

	PR c++/80780
	* cp-gimplify.c (fold_builtin_source_location): Use 2 instead of 0
	as last argument to cxx_printable_name.

	* g++.dg/cpp2a/srcloc1.C (quux): Use __PRETTY_FUNCTION__ instead of
	function.
	* g++.dg/cpp2a/srcloc2.C (quux): Likewise.
	* g++.dg/cpp2a/srcloc15.C (S::S): Likewise.
	(bar): Likewise.  Adjust expected column.
	* g++.dg/cpp2a/srcloc17.C (S::S): Likewise.
	(bar): Likewise.  Adjust expected column.

--- gcc/cp/cp-gimplify.c.jj	2020-12-02 12:26:21.596922205 +0100
+++ gcc/cp/cp-gimplify.c	2020-12-02 13:16:48.599284262 +0100
@@ -3001,7 +3001,7 @@ fold_builtin_source_location (location_t
 	      const char *name = "";
 
 	      if (current_function_decl)
-		name = cxx_printable_name (current_function_decl, 0);
+		name = cxx_printable_name (current_function_decl, 2);
 
 	      val = build_string_literal (strlen (name) + 1, name);
 	    }
--- gcc/testsuite/g++.dg/cpp2a/srcloc1.C.jj	2020-07-28 15:39:10.012756173 +0200
+++ gcc/testsuite/g++.dg/cpp2a/srcloc1.C	2020-12-02 13:17:39.010708329 +0100
@@ -88,7 +88,7 @@ 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__;
+  const char *function2 = __PRETTY_FUNCTION__;
   int line1 = source_location::current ().line ();
   int line2 = __LINE__ - 1;
   int column
--- gcc/testsuite/g++.dg/cpp2a/srcloc2.C.jj	2020-07-28 15:39:10.012756173 +0200
+++ gcc/testsuite/g++.dg/cpp2a/srcloc2.C	2020-12-02 13:17:51.851562576 +0100
@@ -92,7 +92,7 @@ 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__;
+  const char *function2 = __PRETTY_FUNCTION__;
   int line1 = source_location::current ().line ();
   int line2 = __LINE__ - 1;
   int column
--- gcc/testsuite/g++.dg/cpp2a/srcloc15.C.jj	2020-12-02 12:48:20.592828477 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc15.C	2020-12-02 13:20:46.768577089 +0100
@@ -44,12 +44,12 @@ struct S {
   source_location loc = source_location::current ();
 
   constexpr S (int l, source_location loc = source_location::current ())
-  : func(__FUNCTION__), line(l), loc(loc)
+  : func(__PRETTY_FUNCTION__), line(l), loc(loc)
   {}
 
   constexpr S (double)
-  : func(__FUNCTION__), line(__LINE__)
-  //                                 ^ column 38
+  : func(__PRETTY_FUNCTION__), line(__LINE__)
+  //                                        ^ column 45
   {}
 };
 
@@ -73,7 +73,7 @@ bar ()
   //                                            ^ column 49
   const source_location *d[3] = { &a, &b, &c };
   const char *file1 = __FILE__;
-  const char *function1 = __FUNCTION__;
+  const char *function1 = __PRETTY_FUNCTION__;
   for (int j = 0; j < 3; j++)
     {
       int i= 0;
@@ -104,7 +104,7 @@ bar ()
     return false;
   if (e.loc.column () != 9)
     return false;
-  if (f.loc.column () != 38)
+  if (f.loc.column () != 45)
     return false;
   return true;
 }
--- gcc/testsuite/g++.dg/cpp2a/srcloc17.C.jj	2020-12-02 12:58:26.113904280 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc17.C	2020-12-02 13:21:11.943291326 +0100
@@ -46,12 +46,12 @@ struct S {
   source_location loc = source_location::current ();
 
   constexpr S (int l, source_location loc = source_location::current ())
-  : func(__FUNCTION__), line(l), loc(loc)
+  : func(__PRETTY_FUNCTION__), line(l), loc(loc)
   {}
 
   constexpr S (double)
-  : func(__FUNCTION__), line(__LINE__)
-  //                                 ^ column 38
+  : func(__PRETTY_FUNCTION__), line(__LINE__)
+  //                                        ^ column 45
   {}
 };
 
@@ -76,7 +76,7 @@ bar ()
   //                                           ^ column 48
   const source_location *d[3] = { &a, &b, &c };
   const char *file1 = __FILE__;
-  const char *function1 = b.function_name ();
+  const char *function1 = __PRETTY_FUNCTION__;
   for (int j = 0; j < 3; j++)
     {
       int i= 0;
@@ -107,7 +107,7 @@ bar ()
     return false;
   if (e.loc.column () != 8)
     return false;
-  if (f.loc.column () != 38)
+  if (f.loc.column () != 45)
     return false;
   return true;
 }


	Jakub


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++, v2: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093]
  2020-12-02 12:13   ` [PATCH] c++, v2: " Jakub Jelinek
@ 2020-12-02 15:19     ` Marek Polacek
  2020-12-02 15:42     ` Jason Merrill
  1 sibling, 0 replies; 13+ messages in thread
From: Marek Polacek @ 2020-12-02 15:19 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jason Merrill, Jonathan Wakely, gcc-patches

On Wed, Dec 02, 2020 at 01:13:26PM +0100, Jakub Jelinek via Gcc-patches wrote:
> 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?

I have a few comments, but only minor things; please feel free to ignore
them.

> --- 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;

You could use id_equal.

> +  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;

And here too.

> +  tree decl
> +    = lookup_qualified_name (std_node,
> +			     DECL_NAME (TYPE_NAME (source_location)),
> +			     LOOK_want::TYPE, tf_none);
> +  return TYPE_NAME (source_location) == decl;

Can this be decl_in_std_namespace_p?

> --- 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;

You could use 

temp_override<tree> ovr (current_function_decl);

to avoid having to restore c_f_d manually.

> +      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);

You can drop the ", NULL_TREE".

Thanks,
Marek


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++, v2: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093]
  2020-12-02 12:13   ` [PATCH] c++, v2: " Jakub Jelinek
  2020-12-02 15:19     ` Marek Polacek
@ 2020-12-02 15:42     ` Jason Merrill
  2020-12-02 17:35       ` [PATCH] c++, v3: " Jakub Jelinek
  1 sibling, 1 reply; 13+ messages in thread
From: Jason Merrill @ 2020-12-02 15:42 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jonathan Wakely, gcc-patches

On 12/2/20 7:13 AM, Jakub Jelinek wrote:
> 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.

Looks like you missed my minor comments within the earlier patch; I 
should have mentioned that there were some.  Repeating them below:

> 2020-12-02  Jakub Jelinek  <jakub@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)

You can use id_equal for comparing identifiers to strings.

> +    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;

TYPE_IDENTIFIER would also make this shorter.

> +
> +  tree decl
> +    = lookup_qualified_name (std_node,
> +			     DECL_NAME (TYPE_NAME (source_location)),
> +			     LOOK_want::TYPE, tf_none);
> +  return TYPE_NAME (source_location) == decl;

Why not TYPE_CONTEXT (source_location) == std_node?  I don't think we 
need to do name lookup here.

> +}
> +
>   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)))

Please factor this condition out into a separate function.

>   	{
>   	  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))

I'd think we would want to do this for any immediate function call that 
happens to make it this far.  Maybe make the source_location_current_p 
test an assert instead of a condition?

> +	    {
> +	      *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
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH] c++, v3: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093]
  2020-12-02 15:42     ` Jason Merrill
@ 2020-12-02 17:35       ` Jakub Jelinek
  2020-12-02 19:00         ` Jason Merrill
  0 siblings, 1 reply; 13+ messages in thread
From: Jakub Jelinek @ 2020-12-02 17:35 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, gcc-patches

On Wed, Dec 02, 2020 at 10:42:51AM -0500, Jason Merrill via Gcc-patches wrote:
> On 12/2/20 7:13 AM, Jakub Jelinek wrote:
> > 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.
> 
> Looks like you missed my minor comments within the earlier patch; I should
> have mentioned that there were some.  Repeating them below:

Oops, I'm terribly sorry, didn't scroll down beyond the Please.
Implemented now yours and Marek's suggestions.

> > +
> > +  tree decl
> > +    = lookup_qualified_name (std_node,
> > +			     DECL_NAME (TYPE_NAME (source_location)),
> > +			     LOOK_want::TYPE, tf_none);
> > +  return TYPE_NAME (source_location) == decl;
> 
> Why not TYPE_CONTEXT (source_location) == std_node?  I don't think we need
> to do name lookup here.

The point was possible inline namespaces between std and source_location.
But Marek's suggestion to use decl_in_std_namespace_p for that looks
right.

Tested on x86_64-linux, ok for trunk if it passes full
bootstrap/regtest on x86_64-linux and i686-linux?

2020-12-02  Jakub Jelinek  <jakub@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 (immediate_invocation_p): New function.
	(build_over_call): Use it.
	* 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-02 18:05:46.497197545 +0100
+++ gcc/cp/cp-tree.h	2020-12-02 18:07:49.395815083 +0100
@@ -7422,6 +7422,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-02 18:05:46.498197533 +0100
+++ gcc/cp/tree.c	2020-12-02 18:27:55.711332497 +0100
@@ -2993,6 +2993,32 @@ 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))
+      || !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;
--- gcc/cp/call.c.jj	2020-12-02 14:42:46.533121244 +0100
+++ gcc/cp/call.c	2020-12-02 18:27:18.607747289 +0100
@@ -8540,6 +8540,25 @@ build_trivial_dtor_call (tree instance,
 		 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
@@ -8607,13 +8626,7 @@ build_over_call (struct z_candidate *can
 				   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))
@@ -9251,13 +9264,7 @@ build_over_call (struct z_candidate *can
   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))
--- gcc/cp/constexpr.c.jj	2020-12-02 14:42:46.551121032 +0100
+++ gcc/cp/constexpr.c	2020-12-02 18:13:16.405150137 +0100
@@ -1332,7 +1332,12 @@ 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));
+    {
+      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;
--- gcc/cp/cp-gimplify.c.jj	2020-12-02 14:42:46.568120832 +0100
+++ gcc/cp/cp-gimplify.c	2020-12-02 18:25:30.380955596 +0100
@@ -1374,6 +1374,14 @@ cp_genericize_r (tree *stmt_p, int *walk
 	  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)))
--- gcc/testsuite/g++.dg/cpp2a/srcloc15.C.jj	2020-12-02 18:07:49.398815049 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc15.C	2020-12-02 18:07:49.398815049 +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 18:07:49.398815049 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc16.C	2020-12-02 18:07:49.398815049 +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 18:07:49.398815049 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc17.C	2020-12-02 18:07:49.398815049 +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 18:07:49.398815049 +0100
+++ gcc/testsuite/g++.dg/cpp2a/srcloc18.C	2020-12-02 18:07:49.398815049 +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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++, v3: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093]
  2020-12-02 17:35       ` [PATCH] c++, v3: " Jakub Jelinek
@ 2020-12-02 19:00         ` Jason Merrill
  0 siblings, 0 replies; 13+ messages in thread
From: Jason Merrill @ 2020-12-02 19:00 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jonathan Wakely, gcc-patches

On 12/2/20 12:35 PM, Jakub Jelinek wrote:
> On Wed, Dec 02, 2020 at 10:42:51AM -0500, Jason Merrill via Gcc-patches wrote:
>> On 12/2/20 7:13 AM, Jakub Jelinek wrote:
>>> 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.
>>
>> Looks like you missed my minor comments within the earlier patch; I should
>> have mentioned that there were some.  Repeating them below:
> 
> Oops, I'm terribly sorry, didn't scroll down beyond the Please.
> Implemented now yours and Marek's suggestions.
> 
>>> +
>>> +  tree decl
>>> +    = lookup_qualified_name (std_node,
>>> +			     DECL_NAME (TYPE_NAME (source_location)),
>>> +			     LOOK_want::TYPE, tf_none);
>>> +  return TYPE_NAME (source_location) == decl;
>>
>> Why not TYPE_CONTEXT (source_location) == std_node?  I don't think we need
>> to do name lookup here.
> 
> The point was possible inline namespaces between std and source_location.
> But Marek's suggestion to use decl_in_std_namespace_p for that looks
> right.
> 
> Tested on x86_64-linux, ok for trunk if it passes full
> bootstrap/regtest on x86_64-linux and i686-linux?

OK.

> 2020-12-02  Jakub Jelinek  <jakub@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 (immediate_invocation_p): New function.
> 	(build_over_call): Use it.
> 	* 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-02 18:05:46.497197545 +0100
> +++ gcc/cp/cp-tree.h	2020-12-02 18:07:49.395815083 +0100
> @@ -7422,6 +7422,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-02 18:05:46.498197533 +0100
> +++ gcc/cp/tree.c	2020-12-02 18:27:55.711332497 +0100
> @@ -2993,6 +2993,32 @@ 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))
> +      || !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;
> --- gcc/cp/call.c.jj	2020-12-02 14:42:46.533121244 +0100
> +++ gcc/cp/call.c	2020-12-02 18:27:18.607747289 +0100
> @@ -8540,6 +8540,25 @@ build_trivial_dtor_call (tree instance,
>   		 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
> @@ -8607,13 +8626,7 @@ build_over_call (struct z_candidate *can
>   				   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))
> @@ -9251,13 +9264,7 @@ build_over_call (struct z_candidate *can
>     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))
> --- gcc/cp/constexpr.c.jj	2020-12-02 14:42:46.551121032 +0100
> +++ gcc/cp/constexpr.c	2020-12-02 18:13:16.405150137 +0100
> @@ -1332,7 +1332,12 @@ 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));
> +    {
> +      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;
> --- gcc/cp/cp-gimplify.c.jj	2020-12-02 14:42:46.568120832 +0100
> +++ gcc/cp/cp-gimplify.c	2020-12-02 18:25:30.380955596 +0100
> @@ -1374,6 +1374,14 @@ cp_genericize_r (tree *stmt_p, int *walk
>   	  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)))
> --- gcc/testsuite/g++.dg/cpp2a/srcloc15.C.jj	2020-12-02 18:07:49.398815049 +0100
> +++ gcc/testsuite/g++.dg/cpp2a/srcloc15.C	2020-12-02 18:07:49.398815049 +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 18:07:49.398815049 +0100
> +++ gcc/testsuite/g++.dg/cpp2a/srcloc16.C	2020-12-02 18:07:49.398815049 +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 18:07:49.398815049 +0100
> +++ gcc/testsuite/g++.dg/cpp2a/srcloc17.C	2020-12-02 18:07:49.398815049 +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 18:07:49.398815049 +0100
> +++ gcc/testsuite/g++.dg/cpp2a/srcloc18.C	2020-12-02 18:07:49.398815049 +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
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++: Change __builtin_source_location to use __PRETTY_FUNCTION__ instead of __FUNCTION__ [PR80780]
  2020-12-02 12:30   ` [PATCH] c++: Change __builtin_source_location to use __PRETTY_FUNCTION__ instead of __FUNCTION__ [PR80780] Jakub Jelinek
@ 2020-12-02 20:18     ` Jason Merrill
  2020-12-02 21:49       ` Jonathan Wakely
  0 siblings, 1 reply; 13+ messages in thread
From: Jason Merrill @ 2020-12-02 20:18 UTC (permalink / raw)
  To: Jakub Jelinek, Jonathan Wakely; +Cc: gcc-patches

On 12/2/20 7:30 AM, Jakub Jelinek wrote:
> Hi!
> 
> On Tue, Dec 01, 2020 at 01:03:52PM +0000, Jonathan Wakely via Gcc-patches wrote:
>> I mentioned in PR 80780 that a __builtin__PRETTY_FUNCTION would have
>> been nice, because __FUNCTION__ isn't very useful for C++, because of
>> overloading and namespace/class scopes. There are an unlimited number
>> of functions that have __FUNCTION__ == "s", e.g. "ns::s(int)" and
>> "ns::s()" and "another_scope::s::s<T...>(T...)" etc.
>>
>> Since __builtin_source_location() can do whatever it wants (without
>> needing to add __builtin__PRETTY_FUNCTION) it might be nice to use the
>> __PRETTY_FUNCTION__ string. JeanHeyd's tests would still need changes,
>> because the name would be "s::s(void*)" not "s::s" but that still
>> seems better for users.
> 
> When I've added template tests for the previous patch, I have noticed that
> the current __builtin_source_location behavior is not really __FUNCTION__,
> just close, because e.g. in function template __FUNCTION__ is still
> "bar" but __builtin_source_location gave "bar<0>".
> 
> Anyway, this patch implements above request to follow __PRETTY_FUNCTION__
> (on top of the earlier posted patch).
> 
> Tested on x86_64-linux, ok for trunk if it passes full bootstrap/regtest on
> x86_64-linux?

OK on Friday unless Jonathan objects.

> 2020-12-02  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/80780
> 	* cp-gimplify.c (fold_builtin_source_location): Use 2 instead of 0
> 	as last argument to cxx_printable_name.
> 
> 	* g++.dg/cpp2a/srcloc1.C (quux): Use __PRETTY_FUNCTION__ instead of
> 	function.
> 	* g++.dg/cpp2a/srcloc2.C (quux): Likewise.
> 	* g++.dg/cpp2a/srcloc15.C (S::S): Likewise.
> 	(bar): Likewise.  Adjust expected column.
> 	* g++.dg/cpp2a/srcloc17.C (S::S): Likewise.
> 	(bar): Likewise.  Adjust expected column.
> 
> --- gcc/cp/cp-gimplify.c.jj	2020-12-02 12:26:21.596922205 +0100
> +++ gcc/cp/cp-gimplify.c	2020-12-02 13:16:48.599284262 +0100
> @@ -3001,7 +3001,7 @@ fold_builtin_source_location (location_t
>   	      const char *name = "";
>   
>   	      if (current_function_decl)
> -		name = cxx_printable_name (current_function_decl, 0);
> +		name = cxx_printable_name (current_function_decl, 2);
>   
>   	      val = build_string_literal (strlen (name) + 1, name);
>   	    }
> --- gcc/testsuite/g++.dg/cpp2a/srcloc1.C.jj	2020-07-28 15:39:10.012756173 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/srcloc1.C	2020-12-02 13:17:39.010708329 +0100
> @@ -88,7 +88,7 @@ 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__;
> +  const char *function2 = __PRETTY_FUNCTION__;
>     int line1 = source_location::current ().line ();
>     int line2 = __LINE__ - 1;
>     int column
> --- gcc/testsuite/g++.dg/cpp2a/srcloc2.C.jj	2020-07-28 15:39:10.012756173 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/srcloc2.C	2020-12-02 13:17:51.851562576 +0100
> @@ -92,7 +92,7 @@ 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__;
> +  const char *function2 = __PRETTY_FUNCTION__;
>     int line1 = source_location::current ().line ();
>     int line2 = __LINE__ - 1;
>     int column
> --- gcc/testsuite/g++.dg/cpp2a/srcloc15.C.jj	2020-12-02 12:48:20.592828477 +0100
> +++ gcc/testsuite/g++.dg/cpp2a/srcloc15.C	2020-12-02 13:20:46.768577089 +0100
> @@ -44,12 +44,12 @@ struct S {
>     source_location loc = source_location::current ();
>   
>     constexpr S (int l, source_location loc = source_location::current ())
> -  : func(__FUNCTION__), line(l), loc(loc)
> +  : func(__PRETTY_FUNCTION__), line(l), loc(loc)
>     {}
>   
>     constexpr S (double)
> -  : func(__FUNCTION__), line(__LINE__)
> -  //                                 ^ column 38
> +  : func(__PRETTY_FUNCTION__), line(__LINE__)
> +  //                                        ^ column 45
>     {}
>   };
>   
> @@ -73,7 +73,7 @@ bar ()
>     //                                            ^ column 49
>     const source_location *d[3] = { &a, &b, &c };
>     const char *file1 = __FILE__;
> -  const char *function1 = __FUNCTION__;
> +  const char *function1 = __PRETTY_FUNCTION__;
>     for (int j = 0; j < 3; j++)
>       {
>         int i= 0;
> @@ -104,7 +104,7 @@ bar ()
>       return false;
>     if (e.loc.column () != 9)
>       return false;
> -  if (f.loc.column () != 38)
> +  if (f.loc.column () != 45)
>       return false;
>     return true;
>   }
> --- gcc/testsuite/g++.dg/cpp2a/srcloc17.C.jj	2020-12-02 12:58:26.113904280 +0100
> +++ gcc/testsuite/g++.dg/cpp2a/srcloc17.C	2020-12-02 13:21:11.943291326 +0100
> @@ -46,12 +46,12 @@ struct S {
>     source_location loc = source_location::current ();
>   
>     constexpr S (int l, source_location loc = source_location::current ())
> -  : func(__FUNCTION__), line(l), loc(loc)
> +  : func(__PRETTY_FUNCTION__), line(l), loc(loc)
>     {}
>   
>     constexpr S (double)
> -  : func(__FUNCTION__), line(__LINE__)
> -  //                                 ^ column 38
> +  : func(__PRETTY_FUNCTION__), line(__LINE__)
> +  //                                        ^ column 45
>     {}
>   };
>   
> @@ -76,7 +76,7 @@ bar ()
>     //                                           ^ column 48
>     const source_location *d[3] = { &a, &b, &c };
>     const char *file1 = __FILE__;
> -  const char *function1 = b.function_name ();
> +  const char *function1 = __PRETTY_FUNCTION__;
>     for (int j = 0; j < 3; j++)
>       {
>         int i= 0;
> @@ -107,7 +107,7 @@ bar ()
>       return false;
>     if (e.loc.column () != 8)
>       return false;
> -  if (f.loc.column () != 38)
> +  if (f.loc.column () != 45)
>       return false;
>     return true;
>   }
> 
> 
> 	Jakub
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] c++: Change __builtin_source_location to use __PRETTY_FUNCTION__ instead of __FUNCTION__ [PR80780]
  2020-12-02 20:18     ` Jason Merrill
@ 2020-12-02 21:49       ` Jonathan Wakely
  0 siblings, 0 replies; 13+ messages in thread
From: Jonathan Wakely @ 2020-12-02 21:49 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jakub Jelinek, gcc-patches

On 02/12/20 15:18 -0500, Jason Merrill wrote:
>On 12/2/20 7:30 AM, Jakub Jelinek wrote:
>>Hi!
>>
>>On Tue, Dec 01, 2020 at 01:03:52PM +0000, Jonathan Wakely via Gcc-patches wrote:
>>>I mentioned in PR 80780 that a __builtin__PRETTY_FUNCTION would have
>>>been nice, because __FUNCTION__ isn't very useful for C++, because of
>>>overloading and namespace/class scopes. There are an unlimited number
>>>of functions that have __FUNCTION__ == "s", e.g. "ns::s(int)" and
>>>"ns::s()" and "another_scope::s::s<T...>(T...)" etc.
>>>
>>>Since __builtin_source_location() can do whatever it wants (without
>>>needing to add __builtin__PRETTY_FUNCTION) it might be nice to use the
>>>__PRETTY_FUNCTION__ string. JeanHeyd's tests would still need changes,
>>>because the name would be "s::s(void*)" not "s::s" but that still
>>>seems better for users.
>>
>>When I've added template tests for the previous patch, I have noticed that
>>the current __builtin_source_location behavior is not really __FUNCTION__,
>>just close, because e.g. in function template __FUNCTION__ is still
>>"bar" but __builtin_source_location gave "bar<0>".
>>
>>Anyway, this patch implements above request to follow __PRETTY_FUNCTION__
>>(on top of the earlier posted patch).
>>
>>Tested on x86_64-linux, ok for trunk if it passes full bootstrap/regtest on
>>x86_64-linux?
>
>OK on Friday unless Jonathan objects.

I'll try to test it tomorrow, but I'm definitely in favour of the
change to PRETTY_FUNCTION.


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2020-12-02 21:49 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-01  8:59 [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093] Jakub Jelinek
2020-12-01 13:03 ` Jonathan Wakely
2020-12-01 15:00   ` Jakub Jelinek
2020-12-02 12:30   ` [PATCH] c++: Change __builtin_source_location to use __PRETTY_FUNCTION__ instead of __FUNCTION__ [PR80780] Jakub Jelinek
2020-12-02 20:18     ` Jason Merrill
2020-12-02 21:49       ` Jonathan Wakely
2020-12-01 21:05 ` [PATCH] c++: Implement LWG3396 Clarify point of reference for source_location::current() [PR80780, PR93093] Jason Merrill
2020-12-01 21:21   ` Jakub Jelinek
2020-12-02 12:13   ` [PATCH] c++, v2: " Jakub Jelinek
2020-12-02 15:19     ` Marek Polacek
2020-12-02 15:42     ` Jason Merrill
2020-12-02 17:35       ` [PATCH] c++, v3: " Jakub Jelinek
2020-12-02 19:00         ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).