On 10/29/18 9:37 AM, Jason Merrill wrote:
On Fri, Oct 26, 2018 at 3:14 AM Martin Liška <mli...@suse.cz> wrote:
On 10/24/18 7:24 PM, Jason Merrill wrote:
On Tue, Oct 23, 2018 at 4:59 AM Martin Liška <mli...@suse.cz> wrote:
However, I still see some minor ICEs, it's probably related to decay_conversion
in cp_fname_init:
1) ./xg++ -B.
/home/marxin/Programming/gcc/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C
/home/marxin/Programming/gcc/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C:6:17:
internal compiler error: Segmentation fault
6 | [] { return __func__; }();
| ^~~~~~~~
0x1344568 crash_signal
/home/marxin/Programming/gcc/gcc/toplev.c:325
0x7ffff6bc310f ???
/usr/src/debug/glibc-2.27-6.1.x86_64/signal/../sysdeps/unix/sysv/linux/x86_64/sigaction.c:0
0x9db134 is_capture_proxy(tree_node*)
Hi.
The problem in both tests is that is_capture_proxy thinks your
__func__ VAR_DECL with DECL_VALUE_EXPR is a capture proxy, since it is
neither an anonymous union proxy nor a structured binding.
I see, however I'm a rookie in area of C++ FE. Would it be solvable this problem
with lambdas?
The standard says,
The function-local predefined variable __func__ is defined as if a
definition of the form
static const char __func__[] = "function-name ";
had been provided, where function-name is an implementation-defined
string. It is unspecified whether such a variable has an address
distinct from that of any other object in the program.
So changing the type of __func__ (from array to pointer) still breaks
conformance. And we need to keep the type checks from pretty4.C, even
though the checks for strings being distinct need to go.
I added following patch which puts back type to const char[] (instead of char *)
and I made the variable static. Now I see pretty4.C testcase passing again.
To be honest I'm not convinced about the FE changes, so a help would
be appreciated.
OK, I'll poke at it.
This further patch teaches is_capture_proxy about function-name
variables, and changes the handling of __PRETTY_FUNCTION__ in template
instantiations to create new variables rather than instantiations.
The C++ changes are OK with this.
commit 100f6f38f9d8bbb5d77ba7a4ccb86a4c85aa2cd9
Author: Jason Merrill <ja...@redhat.com>
Date: Mon Oct 29 22:35:59 2018 -0400
fname-p
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8454cb4e178..f1a10297e79 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3122,6 +3122,14 @@ struct GTY(()) lang_decl {
(DECL_NAME (NODE) \
&& id_equal (DECL_NAME (NODE), "__PRETTY_FUNCTION__"))
+/* For a DECL, true if it is __func__ or similar. */
+#define DECL_FNAME_P(NODE) \
+ (VAR_P (NODE) && DECL_NAME (NODE) && DECL_ARTIFICIAL (NODE) \
+ && DECL_HAS_VALUE_EXPR_P (NODE) \
+ && (id_equal (DECL_NAME (NODE), "__PRETTY_FUNCTION__") \
+ || id_equal (DECL_NAME (NODE), "__FUNCTION__") \
+ || id_equal (DECL_NAME (NODE), "__func__")))
+
/* Nonzero if the variable was declared to be thread-local.
We need a special C++ version of this test because the middle-end
DECL_THREAD_LOCAL_P uses the symtab, so we can't use it for
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index cce9cc99ff1..bde8023ce3b 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4465,7 +4465,7 @@ cp_fname_init (const char* name, tree *type_p)
static tree
cp_make_fname_decl (location_t loc, tree id, int type_dep)
{
- const char *const name = (type_dep && processing_template_decl
+ const char *const name = (type_dep && in_template_function ()
? NULL : fname_as_string (type_dep));
tree type;
tree init = cp_fname_init (name, &type);
@@ -7064,8 +7064,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
init = NULL_TREE;
release_tree_vector (cleanups);
}
- else if (!DECL_PRETTY_FUNCTION_P (decl))
+ else
{
+ gcc_assert (!DECL_PRETTY_FUNCTION_P (decl));
/* Deduce array size even if the initializer is dependent. */
maybe_deduce_size_from_array_init (decl, init);
/* And complain about multiple initializers. */
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 297327f1ab6..318671bbcd0 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -262,6 +262,7 @@ is_capture_proxy (tree decl)
&& DECL_HAS_VALUE_EXPR_P (decl)
&& !DECL_ANON_UNION_VAR_P (decl)
&& !DECL_DECOMPOSITION_P (decl)
+ && !DECL_FNAME_P (decl)
&& LAMBDA_FUNCTION_P (DECL_CONTEXT (decl)));
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 6975027076e..510264d38a0 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -16702,6 +16702,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
register_local_specialization (inst, decl);
break;
}
+ else if (DECL_PRETTY_FUNCTION_P (decl))
+ decl = make_fname_decl (DECL_SOURCE_LOCATION (decl),
+ DECL_NAME (decl),
+ true/*DECL_PRETTY_FUNCTION_P (decl)*/);
else if (DECL_IMPLICIT_TYPEDEF_P (decl)
&& LAMBDA_TYPE_P (TREE_TYPE (decl)))
/* Don't copy the old closure; we'll create a new one in
@@ -16746,19 +16750,6 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
DECL_CONTEXT (decl) = current_function_decl;
cp_check_omp_declare_reduction (decl);
}
- else if (VAR_P (decl)
- && DECL_PRETTY_FUNCTION_P (decl))
- {
- /* For __PRETTY_FUNCTION__ we have to adjust the
- initializer. */
- const char *const name
- = cxx_printable_name (current_function_decl, 2);
- init = cp_fname_init (name, &TREE_TYPE (decl));
- SET_DECL_VALUE_EXPR (decl, init);
- DECL_HAS_VALUE_EXPR_P (decl) = 1;
- DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
- maybe_push_decl (decl);
- }
else
{
int const_init = false;
diff --git a/gcc/testsuite/g++.old-deja/g++.ext/pretty4.C b/gcc/testsuite/g++.old-deja/g++.ext/pretty4.C
new file mode 100644
index 00000000000..eb5d0de5cc6
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.ext/pretty4.C
@@ -0,0 +1,39 @@
+// { dg-do run }
+// Copyright (C) 2000 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 3 Mar 2000 <nat...@codesourcery.com>
+
+// __PRETTY_FUNCTION__, __FUNCTION__ and __function__ should have the
+// type char const [X], where X is the right value for that particular function
+
+static int fail;
+
+void unover (char const (*)[5]) {}
+void foo (char const (*)[5]) {}
+void foo (void *) {fail = 1;}
+void foo (void const *) {fail = 1;}
+void baz (char const (&)[5]) {}
+
+void baz ()
+{
+ static void const *ptr = __FUNCTION__;
+ // all uses should be the same.
+ if (ptr != __FUNCTION__)
+ fail = 1;
+}
+
+int main ()
+{
+ // make sure we actually emit the VAR_DECL when needed, and things have the
+ // expected type.
+ foo (&__FUNCTION__);
+ baz (__FUNCTION__);
+ unover (&__FUNCTION__);
+ if (fail)
+ return 1;
+
+ baz ();
+ if (fail)
+ return 1;
+
+ return 0;
+}