diff mbox series

[C++,debug,PR88534] accept VAR_DECL in class literal template parms

Message ID or8sxhkybq.fsf@lxoliva.fsfla.org
State New
Headers show
Series [C++,debug,PR88534] accept VAR_DECL in class literal template parms | expand

Commit Message

Alexandre Oliva March 14, 2019, 8:14 p.m. UTC
P0732R2 / C++ 2a introduce class literals as template parameters.  The
front-end uses VAR_DECLs constructed from such literals to bind the
template PARM_DECLs, but dwarf2out.c used to reject such VAR_DECLs.

Taking DECL_INITIAL from such VAR_DECLs enables the generation of
DW_AT_const_value for them, at least when the class literal can
actually be represented as such.

Regstrapped on x86_64- and i686-linux-gnu.  Ok to install?


for  gcc/ChangeLog

	PR c++/88534
	PR c++/88537
	* dwarf2out.c (generic_parameter_die): Follow DECL_INITIAL of
	VAR_DECL args.

for  gcc/ChangeLog

	PR c++/88534
	PR c++/88537
	* g++.dg/cpp2a/pr88534.C: New.
	* g++.dg/cpp2a/pr88537.C: New.
---
 gcc/dwarf2out.c                      |    7 ++++
 gcc/testsuite/g++.dg/cpp2a/pr88534.C |   65 ++++++++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/pr88537.C |   16 ++++++++
 3 files changed, 88 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/pr88534.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/pr88537.C

Comments

Marek Polacek March 14, 2019, 8:20 p.m. UTC | #1
On Thu, Mar 14, 2019 at 05:14:49PM -0300, Alexandre Oliva wrote:
> P0732R2 / C++ 2a introduce class literals as template parameters.  The
> front-end uses VAR_DECLs constructed from such literals to bind the
> template PARM_DECLs, but dwarf2out.c used to reject such VAR_DECLs.
> 
> Taking DECL_INITIAL from such VAR_DECLs enables the generation of
> DW_AT_const_value for them, at least when the class literal can
> actually be represented as such.
> 
> Regstrapped on x86_64- and i686-linux-gnu.  Ok to install?
> 
> 
> for  gcc/ChangeLog
> 
> 	PR c++/88534
> 	PR c++/88537
> 	* dwarf2out.c (generic_parameter_die): Follow DECL_INITIAL of
> 	VAR_DECL args.
> 
> for  gcc/ChangeLog
> 
> 	PR c++/88534
> 	PR c++/88537
> 	* g++.dg/cpp2a/pr88534.C: New.
> 	* g++.dg/cpp2a/pr88537.C: New.
> ---
>  gcc/dwarf2out.c                      |    7 ++++
>  gcc/testsuite/g++.dg/cpp2a/pr88534.C |   65 ++++++++++++++++++++++++++++++++++
>  gcc/testsuite/g++.dg/cpp2a/pr88537.C |   16 ++++++++
>  3 files changed, 88 insertions(+)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/pr88534.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/pr88537.C
> 
> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
> index 8305555681447..478d9b9b289b1 100644
> --- a/gcc/dwarf2out.c
> +++ b/gcc/dwarf2out.c
> @@ -13601,6 +13601,13 @@ generic_parameter_die (tree parm, tree arg,
>    dw_die_ref tmpl_die = NULL;
>    const char *name = NULL;
>  
> +  /* C++2a accepts class literals as template parameters, and var
> +     decls with initializers represent them.  The VAR_DECLs would be
> +     rejected, but we can take the DECL_INITIAL constructor and
> +     attempt to expand it.  */
> +  if (TREE_CODE (arg) == VAR_DECL)

You can use VAR_P for this.

Marek
Jason Merrill March 14, 2019, 8:24 p.m. UTC | #2
On 3/14/19 4:20 PM, Marek Polacek wrote:
> On Thu, Mar 14, 2019 at 05:14:49PM -0300, Alexandre Oliva wrote:
>> P0732R2 / C++ 2a introduce class literals as template parameters.  The
>> front-end uses VAR_DECLs constructed from such literals to bind the
>> template PARM_DECLs, but dwarf2out.c used to reject such VAR_DECLs.
>>
>> Taking DECL_INITIAL from such VAR_DECLs enables the generation of
>> DW_AT_const_value for them, at least when the class literal can
>> actually be represented as such.
>>
>> Regstrapped on x86_64- and i686-linux-gnu.  Ok to install?
>>
>>
>> for  gcc/ChangeLog
>>
>> 	PR c++/88534
>> 	PR c++/88537
>> 	* dwarf2out.c (generic_parameter_die): Follow DECL_INITIAL of
>> 	VAR_DECL args.
>>
>> for  gcc/ChangeLog
>>
>> 	PR c++/88534
>> 	PR c++/88537
>> 	* g++.dg/cpp2a/pr88534.C: New.
>> 	* g++.dg/cpp2a/pr88537.C: New.
>> ---
>>   gcc/dwarf2out.c                      |    7 ++++
>>   gcc/testsuite/g++.dg/cpp2a/pr88534.C |   65 ++++++++++++++++++++++++++++++++++
>>   gcc/testsuite/g++.dg/cpp2a/pr88537.C |   16 ++++++++
>>   3 files changed, 88 insertions(+)
>>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/pr88534.C
>>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/pr88537.C
>>
>> diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
>> index 8305555681447..478d9b9b289b1 100644
>> --- a/gcc/dwarf2out.c
>> +++ b/gcc/dwarf2out.c
>> @@ -13601,6 +13601,13 @@ generic_parameter_die (tree parm, tree arg,
>>     dw_die_ref tmpl_die = NULL;
>>     const char *name = NULL;
>>   
>> +  /* C++2a accepts class literals as template parameters, and var
>> +     decls with initializers represent them.  The VAR_DECLs would be
>> +     rejected, but we can take the DECL_INITIAL constructor and
>> +     attempt to expand it.  */
>> +  if (TREE_CODE (arg) == VAR_DECL)
> 
> You can use VAR_P for this.

OK with that change.

Jason
Alexandre Oliva March 15, 2019, 1:53 p.m. UTC | #3
On Mar 14, 2019, Jason Merrill <jason@redhat.com> wrote:

>> You can use VAR_P for this.

> OK with that change.

Thanks, I went ahead and also added a test before dereferencing it,
since there was evidence shortly thereafter that it could possibly be
NULL.

Here's what I'm installing.


P0732R2 / C++ 2a introduce class literals as template parameters.  The
front-end uses VAR_DECLs constructed from such literals to bind the
template PARM_DECLs, but dwarf2out.c used to reject such VAR_DECLs.

Taking DECL_INITIAL from such VAR_DECLs enables the generation of
DW_AT_const_value for them, at least when the class literal can
actually be represented as such.


for  gcc/ChangeLog

	PR c++/88534
	PR c++/88537
	* dwarf2out.c (generic_parameter_die): Follow DECL_INITIAL of
	VAR_DECL args.

for  gcc/ChangeLog

	PR c++/88534
	PR c++/88537
	* g++.dg/cpp2a/pr88534.C: New.
	* g++.dg/cpp2a/pr88537.C: New.
---
 gcc/dwarf2out.c                      |    7 ++++
 gcc/testsuite/g++.dg/cpp2a/pr88534.C |   65 ++++++++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/pr88537.C |   16 ++++++++
 3 files changed, 88 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/pr88534.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/pr88537.C

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index d9cefd3e1d3cf..251fff7b9ae96 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -13603,6 +13603,13 @@ generic_parameter_die (tree parm, tree arg,
   dw_die_ref tmpl_die = NULL;
   const char *name = NULL;
 
+  /* C++2a accepts class literals as template parameters, and var
+     decls with initializers represent them.  The VAR_DECLs would be
+     rejected, but we can take the DECL_INITIAL constructor and
+     attempt to expand it.  */
+  if (arg && VAR_P (arg))
+    arg = DECL_INITIAL (arg);
+
   if (!parm || !DECL_NAME (parm) || !arg)
     return NULL;
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/pr88534.C b/gcc/testsuite/g++.dg/cpp2a/pr88534.C
new file mode 100644
index 0000000000000..54faf385f11aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/pr88534.C
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++2a } }
+// { dg-options "-g" }
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std
+{
+
+template <typename T, T... I>
+struct integer_sequence
+{
+  typedef T value_type;
+  static constexpr size_t size () noexcept { return sizeof...(I); }
+};
+
+template <typename T, T N>
+using make_integer_sequence = integer_sequence<T, __integer_pack (N)...>;
+
+template <size_t... I>
+using index_sequence = integer_sequence<size_t, I...>;
+
+template <size_t N>
+using make_index_sequence = make_integer_sequence<size_t, N>;
+}
+
+template <typename T, size_t N> struct S
+{
+  T content[N];
+  using char_type = T;
+  template <size_t... I>
+  constexpr S (const T (&input)[N], std::index_sequence<I...>) noexcept : content{input[I]...} { }
+  constexpr S (const T (&input)[N]) noexcept : S (input, std::make_index_sequence<N> ()) { }
+  constexpr size_t size () const noexcept
+  {
+    if (content[N - 1] == '\0')
+      return N - 1;
+    else
+      return N;
+  }
+  constexpr T operator[] (size_t i) const noexcept
+  {
+    return content[i];
+  }
+  constexpr const T *begin () const noexcept
+  {
+    return content;
+  }
+  constexpr const T *end () const noexcept
+  {
+    return content + size ();
+  }
+};
+
+template <typename T, size_t N> S (const T (&)[N]) -> S<T, N>;
+
+template <S S>
+struct F
+{
+};
+
+auto
+foo ()
+{
+  F<"test"> f;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/pr88537.C b/gcc/testsuite/g++.dg/cpp2a/pr88537.C
new file mode 100644
index 0000000000000..d558d45f57830
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/pr88537.C
@@ -0,0 +1,16 @@
+// { dg-do compile { target c++2a } }
+// { dg-options "-g" }
+
+struct pair {
+	unsigned a;
+	unsigned b;
+	constexpr pair(unsigned _a, unsigned _b) noexcept: a{_a}, b{_b} { }
+};
+
+template <pair p> void fnc() {
+	
+}
+
+void f() {
+    fnc<pair(10,20)>();
+}
Marek Polacek March 20, 2019, 4:50 p.m. UTC | #4
On Fri, Mar 15, 2019 at 10:53:35AM -0300, Alexandre Oliva wrote:
> On Mar 14, 2019, Jason Merrill <jason@redhat.com> wrote:
> 
> >> You can use VAR_P for this.
> 
> > OK with that change.
> 
> Thanks, I went ahead and also added a test before dereferencing it,
> since there was evidence shortly thereafter that it could possibly be
> NULL.
> 
> Here's what I'm installing.
> 
> 
> P0732R2 / C++ 2a introduce class literals as template parameters.  The
> front-end uses VAR_DECLs constructed from such literals to bind the
> template PARM_DECLs, but dwarf2out.c used to reject such VAR_DECLs.
> 
> Taking DECL_INITIAL from such VAR_DECLs enables the generation of
> DW_AT_const_value for them, at least when the class literal can
> actually be represented as such.
> 
> 
> for  gcc/ChangeLog
> 
> 	PR c++/88534
> 	PR c++/88537
> 	* dwarf2out.c (generic_parameter_die): Follow DECL_INITIAL of
> 	VAR_DECL args.
> 
> for  gcc/ChangeLog
> 
> 	PR c++/88534
> 	PR c++/88537
> 	* g++.dg/cpp2a/pr88534.C: New.

This test fails with
pr88534.C:58:1: sorry, unimplemented: string literal in function template signature

Marek
Alexandre Oliva March 20, 2019, 7:56 p.m. UTC | #5
On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:

> This test fails with
> pr88534.C:58:1: sorry, unimplemented: string literal in function template signature

Interesting...  gcc-8 rejected it with an error message rejecting the
template parameter, but my latest trunk build (dated Mar 13, r269641)
compiles it all right.  Was there a subsequent fix, maybe?  I didn't
realize it was supposed to be rejected.
Marek Polacek March 20, 2019, 9:55 p.m. UTC | #6
On Wed, Mar 20, 2019 at 04:56:33PM -0300, Alexandre Oliva wrote:
> On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:
> 
> > This test fails with
> > pr88534.C:58:1: sorry, unimplemented: string literal in function template signature
> 
> Interesting...  gcc-8 rejected it with an error message rejecting the
> template parameter, but my latest trunk build (dated Mar 13, r269641)
> compiles it all right.  Was there a subsequent fix, maybe?  I didn't
> realize it was supposed to be rejected.

Ah, that problem only started with r269814, namely this hunk:

--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -824,10 +824,9 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
       value = digest_init_flags (type, init, flags, tf_warning_or_error);
     }
 
-  if (TREE_CODE (type) == ARRAY_TYPE
-      && TYPE_STRING_FLAG (TREE_TYPE (type))
-      && TREE_CODE (value) == CONSTRUCTOR)
-    value = braced_list_to_string (type, value);
+  /* Look for braced array initializers for character arrays and
+     recursively convert them into STRING_CSTs.  */
+  value = braced_lists_to_strings (type, value);
 
   current_ref_temp_count = 0;
   value = extend_ref_init_temps (decl, value, cleanups);

which now changes

  {.content={116, 101, 115, 116, 0}}

to

  {.content="test"}

Marek
Jakub Jelinek March 20, 2019, 9:58 p.m. UTC | #7
On Wed, Mar 20, 2019 at 05:55:04PM -0400, Marek Polacek wrote:
> On Wed, Mar 20, 2019 at 04:56:33PM -0300, Alexandre Oliva wrote:
> > On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:
> > 
> > > This test fails with
> > > pr88534.C:58:1: sorry, unimplemented: string literal in function template signature
> > 
> > Interesting...  gcc-8 rejected it with an error message rejecting the
> > template parameter, but my latest trunk build (dated Mar 13, r269641)
> > compiles it all right.  Was there a subsequent fix, maybe?  I didn't
> > realize it was supposed to be rejected.
> 
> Ah, that problem only started with r269814, namely this hunk:

Maybe this is done too early and should be postponed to genericization
(perhaps except for TREE_STATIC vars)?

> --- a/gcc/cp/typeck2.c
> +++ b/gcc/cp/typeck2.c
> @@ -824,10 +824,9 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
>        value = digest_init_flags (type, init, flags, tf_warning_or_error);
>      }
>  
> -  if (TREE_CODE (type) == ARRAY_TYPE
> -      && TYPE_STRING_FLAG (TREE_TYPE (type))
> -      && TREE_CODE (value) == CONSTRUCTOR)
> -    value = braced_list_to_string (type, value);
> +  /* Look for braced array initializers for character arrays and
> +     recursively convert them into STRING_CSTs.  */
> +  value = braced_lists_to_strings (type, value);
>  
>    current_ref_temp_count = 0;
>    value = extend_ref_init_temps (decl, value, cleanups);
> 
> which now changes
> 
>   {.content={116, 101, 115, 116, 0}}
> 
> to
> 
>   {.content="test"}
> 
> Marek

	Jakub
Marek Polacek March 20, 2019, 10:06 p.m. UTC | #8
On Wed, Mar 20, 2019 at 10:58:32PM +0100, Jakub Jelinek wrote:
> On Wed, Mar 20, 2019 at 05:55:04PM -0400, Marek Polacek wrote:
> > On Wed, Mar 20, 2019 at 04:56:33PM -0300, Alexandre Oliva wrote:
> > > On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:
> > > 
> > > > This test fails with
> > > > pr88534.C:58:1: sorry, unimplemented: string literal in function template signature
> > > 
> > > Interesting...  gcc-8 rejected it with an error message rejecting the
> > > template parameter, but my latest trunk build (dated Mar 13, r269641)
> > > compiles it all right.  Was there a subsequent fix, maybe?  I didn't
> > > realize it was supposed to be rejected.
> > 
> > Ah, that problem only started with r269814, namely this hunk:
> 
> Maybe this is done too early and should be postponed to genericization
> (perhaps except for TREE_STATIC vars)?

Or skip when DECL is template_parm_object_p.

> > --- a/gcc/cp/typeck2.c
> > +++ b/gcc/cp/typeck2.c
> > @@ -824,10 +824,9 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
> >        value = digest_init_flags (type, init, flags, tf_warning_or_error);
> >      }
> >  
> > -  if (TREE_CODE (type) == ARRAY_TYPE
> > -      && TYPE_STRING_FLAG (TREE_TYPE (type))
> > -      && TREE_CODE (value) == CONSTRUCTOR)
> > -    value = braced_list_to_string (type, value);
> > +  /* Look for braced array initializers for character arrays and
> > +     recursively convert them into STRING_CSTs.  */
> > +  value = braced_lists_to_strings (type, value);
> >  
> >    current_ref_temp_count = 0;
> >    value = extend_ref_init_temps (decl, value, cleanups);
> > 
> > which now changes
> > 
> >   {.content={116, 101, 115, 116, 0}}
> > 
> > to
> > 
> >   {.content="test"}

Marek
Jason Merrill March 21, 2019, 7:03 p.m. UTC | #9
On 3/20/19 6:06 PM, Marek Polacek wrote:
> On Wed, Mar 20, 2019 at 10:58:32PM +0100, Jakub Jelinek wrote:
>> On Wed, Mar 20, 2019 at 05:55:04PM -0400, Marek Polacek wrote:
>>> On Wed, Mar 20, 2019 at 04:56:33PM -0300, Alexandre Oliva wrote:
>>>> On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:
>>>>
>>>>> This test fails with
>>>>> pr88534.C:58:1: sorry, unimplemented: string literal in function template signature
>>>>
>>>> Interesting...  gcc-8 rejected it with an error message rejecting the
>>>> template parameter, but my latest trunk build (dated Mar 13, r269641)
>>>> compiles it all right.  Was there a subsequent fix, maybe?  I didn't
>>>> realize it was supposed to be rejected.
>>>
>>> Ah, that problem only started with r269814, namely this hunk:
>>
>> Maybe this is done too early and should be postponed to genericization
>> (perhaps except for TREE_STATIC vars)?
> 
> Or skip when DECL is template_parm_object_p.

Or handle it in mangle.c.  I don't see any reason we shouldn't accept

struct A
{
   char c[4];
};

template <A a> struct B { };
B<A{"FOO"}> b;

Probably we should use the same mangling whether the initializer for c 
was spelled as a string literal or list of integers.

The thing we still don't want to allow is mangling the *address* of a 
string literal.

Jason
Jonathan Wakely March 27, 2019, 10:44 a.m. UTC | #10
On 21/03/19 15:03 -0400, Jason Merrill wrote:
>On 3/20/19 6:06 PM, Marek Polacek wrote:
>>On Wed, Mar 20, 2019 at 10:58:32PM +0100, Jakub Jelinek wrote:
>>>On Wed, Mar 20, 2019 at 05:55:04PM -0400, Marek Polacek wrote:
>>>>On Wed, Mar 20, 2019 at 04:56:33PM -0300, Alexandre Oliva wrote:
>>>>>On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:
>>>>>
>>>>>>This test fails with
>>>>>>pr88534.C:58:1: sorry, unimplemented: string literal in function template signature
>>>>>
>>>>>Interesting...  gcc-8 rejected it with an error message rejecting the
>>>>>template parameter, but my latest trunk build (dated Mar 13, r269641)
>>>>>compiles it all right.  Was there a subsequent fix, maybe?  I didn't
>>>>>realize it was supposed to be rejected.
>>>>
>>>>Ah, that problem only started with r269814, namely this hunk:
>>>
>>>Maybe this is done too early and should be postponed to genericization
>>>(perhaps except for TREE_STATIC vars)?
>>
>>Or skip when DECL is template_parm_object_p.
>
>Or handle it in mangle.c.  I don't see any reason we shouldn't accept
>
>struct A
>{
>  char c[4];
>};
>
>template <A a> struct B { };
>B<A{"FOO"}> b;
>
>Probably we should use the same mangling whether the initializer for c 
>was spelled as a string literal or list of integers.
>
>The thing we still don't want to allow is mangling the *address* of a 
>string literal.

Will that help PR 47488 as well?
Martin Sebor March 27, 2019, 4:24 p.m. UTC | #11
On 3/21/19 1:03 PM, Jason Merrill wrote:
> On 3/20/19 6:06 PM, Marek Polacek wrote:
>> On Wed, Mar 20, 2019 at 10:58:32PM +0100, Jakub Jelinek wrote:
>>> On Wed, Mar 20, 2019 at 05:55:04PM -0400, Marek Polacek wrote:
>>>> On Wed, Mar 20, 2019 at 04:56:33PM -0300, Alexandre Oliva wrote:
>>>>> On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:
>>>>>
>>>>>> This test fails with
>>>>>> pr88534.C:58:1: sorry, unimplemented: string literal in function 
>>>>>> template signature
>>>>>
>>>>> Interesting...  gcc-8 rejected it with an error message rejecting the
>>>>> template parameter, but my latest trunk build (dated Mar 13, r269641)
>>>>> compiles it all right.  Was there a subsequent fix, maybe?  I didn't
>>>>> realize it was supposed to be rejected.
>>>>
>>>> Ah, that problem only started with r269814, namely this hunk:
>>>
>>> Maybe this is done too early and should be postponed to genericization
>>> (perhaps except for TREE_STATIC vars)?
>>
>> Or skip when DECL is template_parm_object_p.
> 
> Or handle it in mangle.c.  I don't see any reason we shouldn't accept
> 
> struct A
> {
>    char c[4];
> };
> 
> template <A a> struct B { };
> B<A{"FOO"}> b;
> 
> Probably we should use the same mangling whether the initializer for c 
> was spelled as a string literal or list of integers.

So just loop over the STRING_CST and mangle each character the same
way as it were an element of the braced initializer list?

Martin

> 
> The thing we still don't want to allow is mangling the *address* of a 
> string literal.
> 
> Jason
Jason Merrill March 27, 2019, 8:53 p.m. UTC | #12
On 3/27/19 12:24 PM, Martin Sebor wrote:
> On 3/21/19 1:03 PM, Jason Merrill wrote:
>> On 3/20/19 6:06 PM, Marek Polacek wrote:
>>> On Wed, Mar 20, 2019 at 10:58:32PM +0100, Jakub Jelinek wrote:
>>>> On Wed, Mar 20, 2019 at 05:55:04PM -0400, Marek Polacek wrote:
>>>>> On Wed, Mar 20, 2019 at 04:56:33PM -0300, Alexandre Oliva wrote:
>>>>>> On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:
>>>>>>
>>>>>>> This test fails with
>>>>>>> pr88534.C:58:1: sorry, unimplemented: string literal in function 
>>>>>>> template signature
>>>>>>
>>>>>> Interesting...  gcc-8 rejected it with an error message rejecting the
>>>>>> template parameter, but my latest trunk build (dated Mar 13, r269641)
>>>>>> compiles it all right.  Was there a subsequent fix, maybe?  I didn't
>>>>>> realize it was supposed to be rejected.
>>>>>
>>>>> Ah, that problem only started with r269814, namely this hunk:
>>>>
>>>> Maybe this is done too early and should be postponed to genericization
>>>> (perhaps except for TREE_STATIC vars)?
>>>
>>> Or skip when DECL is template_parm_object_p.
>>
>> Or handle it in mangle.c.  I don't see any reason we shouldn't accept
>>
>> struct A
>> {
>>    char c[4];
>> };
>>
>> template <A a> struct B { };
>> B<A{"FOO"}> b;
>>
>> Probably we should use the same mangling whether the initializer for c 
>> was spelled as a string literal or list of integers.
> 
> So just loop over the STRING_CST and mangle each character the same
> way as it were an element of the braced initializer list?

That's probably best, yes.

Jason
Martin Sebor March 27, 2019, 9:11 p.m. UTC | #13
On 3/27/19 4:44 AM, Jonathan Wakely wrote:
> On 21/03/19 15:03 -0400, Jason Merrill wrote:
>> On 3/20/19 6:06 PM, Marek Polacek wrote:
>>> On Wed, Mar 20, 2019 at 10:58:32PM +0100, Jakub Jelinek wrote:
>>>> On Wed, Mar 20, 2019 at 05:55:04PM -0400, Marek Polacek wrote:
>>>>> On Wed, Mar 20, 2019 at 04:56:33PM -0300, Alexandre Oliva wrote:
>>>>>> On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:
>>>>>>
>>>>>>> This test fails with
>>>>>>> pr88534.C:58:1: sorry, unimplemented: string literal in function 
>>>>>>> template signature
>>>>>>
>>>>>> Interesting...  gcc-8 rejected it with an error message rejecting the
>>>>>> template parameter, but my latest trunk build (dated Mar 13, r269641)
>>>>>> compiles it all right.  Was there a subsequent fix, maybe?  I didn't
>>>>>> realize it was supposed to be rejected.
>>>>>
>>>>> Ah, that problem only started with r269814, namely this hunk:
>>>>
>>>> Maybe this is done too early and should be postponed to genericization
>>>> (perhaps except for TREE_STATIC vars)?
>>>
>>> Or skip when DECL is template_parm_object_p.
>>
>> Or handle it in mangle.c.  I don't see any reason we shouldn't accept
>>
>> struct A
>> {
>>  char c[4];
>> };
>>
>> template <A a> struct B { };
>> B<A{"FOO"}> b;
>>
>> Probably we should use the same mangling whether the initializer for c 
>> was spelled as a string literal or list of integers.
>>
>> The thing we still don't want to allow is mangling the *address* of a 
>> string literal.
> 
> Will that help PR 47488 as well?

What I have (attached) accepts all three test cases from PR 47488
(comment #0, #1, #2, and #5) but with different mangling.

The difference in the mangling of the function in the test case
in comment #0 is

   Clang: _Z1gIiEDTcl1fcvT__ELA1_KcEEERKS0_
   GCC 9: _Z1gIiEDTcl1fcvT__ELKc0EEERKS0_

I'm not very familiar with the C++ ABI mangling but from what
I can tell, Clang treats the type as a literal array of 1 const
char element (LA1_Kc) without actually encoding its value, while
with my patch GCC encodes it as a constant literal initializer
consisting of 1 null char (LKc0).  In other words, Clang would
mangle these two the same for the same T:

   template < typename T >
   decltype (f (T(), "123")) g (const T&);

   template < typename T >
   decltype (f (T(), "abc")) g (const T&);

while GCC would mangle them differently.

Which is correct?  Clang's seems correct in this case but would
it also be correct to mangle Jason's B<A{"FOO"}> the same as
B<A{"BAR"}>?

Martin
PR c++/89833 - sorry, unimplemented: string literal in function template signature

gcc/cp/ChangeLog:

	PR c++/89833
	* mangle.c (write_expression): Convert braced initializer lists
	to STRING_CSTs.
	(write_template_arg_literal): Mangle strings the same as braced
	initializer lists.

Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c	(revision 269965)
+++ gcc/cp/mangle.c	(working copy)
@@ -3136,6 +3136,10 @@ write_expression (tree expr)
     }
   else if (code == CONSTRUCTOR)
     {
+      /* Convert braced initializer lists to STRING_CSTs so that
+	 A<"Foo"> and A<{'F', 'o', 'o', 0}> mangle the same.  */
+      expr = braced_lists_to_strings (TREE_TYPE (expr), expr);
+
       vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (expr);
       unsigned i; tree val;
 
@@ -3354,8 +3358,13 @@ static void
 write_template_arg_literal (const tree value)
 {
   write_char ('L');
-  write_type (TREE_TYPE (value));
 
+  tree valtype = TREE_TYPE (value);
+  if (TREE_CODE (value) == STRING_CST)
+    valtype = TREE_TYPE (valtype);
+
+  write_type (valtype);
+
   /* Write a null member pointer value as (type)0, regardless of its
      real representation.  */
   if (null_member_pointer_value_p (value))
@@ -3397,7 +3406,15 @@ write_template_arg_literal (const tree value)
 	break;
 
       case STRING_CST:
-	sorry ("string literal in function template signature");
+	/* Mangle strings the same as braced initializer lists.  */
+	for (const char *p = TREE_STRING_POINTER (value); ; ++p)
+	  {
+	    write_unsigned_number (*(const unsigned char*)p);
+	    if (!*p)
+	      break;
+	    write_string ("EL");
+	    write_type (valtype);
+	  }
 	break;
 
       default:
Martin Sebor March 27, 2019, 10:56 p.m. UTC | #14
On 3/27/19 3:11 PM, Martin Sebor wrote:
> On 3/27/19 4:44 AM, Jonathan Wakely wrote:
>> On 21/03/19 15:03 -0400, Jason Merrill wrote:
>>> On 3/20/19 6:06 PM, Marek Polacek wrote:
>>>> On Wed, Mar 20, 2019 at 10:58:32PM +0100, Jakub Jelinek wrote:
>>>>> On Wed, Mar 20, 2019 at 05:55:04PM -0400, Marek Polacek wrote:
>>>>>> On Wed, Mar 20, 2019 at 04:56:33PM -0300, Alexandre Oliva wrote:
>>>>>>> On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:
>>>>>>>
>>>>>>>> This test fails with
>>>>>>>> pr88534.C:58:1: sorry, unimplemented: string literal in function 
>>>>>>>> template signature
>>>>>>>
>>>>>>> Interesting...  gcc-8 rejected it with an error message rejecting 
>>>>>>> the
>>>>>>> template parameter, but my latest trunk build (dated Mar 13, 
>>>>>>> r269641)
>>>>>>> compiles it all right.  Was there a subsequent fix, maybe?  I didn't
>>>>>>> realize it was supposed to be rejected.
>>>>>>
>>>>>> Ah, that problem only started with r269814, namely this hunk:
>>>>>
>>>>> Maybe this is done too early and should be postponed to genericization
>>>>> (perhaps except for TREE_STATIC vars)?
>>>>
>>>> Or skip when DECL is template_parm_object_p.
>>>
>>> Or handle it in mangle.c.  I don't see any reason we shouldn't accept
>>>
>>> struct A
>>> {
>>>  char c[4];
>>> };
>>>
>>> template <A a> struct B { };
>>> B<A{"FOO"}> b;
>>>
>>> Probably we should use the same mangling whether the initializer for 
>>> c was spelled as a string literal or list of integers.
>>>
>>> The thing we still don't want to allow is mangling the *address* of a 
>>> string literal.
>>
>> Will that help PR 47488 as well?
> 
> What I have (attached) accepts all three test cases from PR 47488
> (comment #0, #1, #2, and #5) but with different mangling.
> 
> The difference in the mangling of the function in the test case
> in comment #0 is
> 
>    Clang: _Z1gIiEDTcl1fcvT__ELA1_KcEEERKS0_
>    GCC 9: _Z1gIiEDTcl1fcvT__ELKc0EEERKS0_
> 
> I'm not very familiar with the C++ ABI mangling but from what
> I can tell, Clang treats the type as a literal array of 1 const
> char element (LA1_Kc) without actually encoding its value, while
> with my patch GCC encodes it as a constant literal initializer
> consisting of 1 null char (LKc0).  In other words, Clang would
> mangle these two the same for the same T:
> 
>    template < typename T >
>    decltype (f (T(), "123")) g (const T&);
> 
>    template < typename T >
>    decltype (f (T(), "abc")) g (const T&);
> 
> while GCC would mangle them differently.
> 
> Which is correct?  Clang's seems correct in this case but would
> it also be correct to mangle Jason's B<A{"FOO"}> the same as
> B<A{"BAR"}>?

After some poking around I found the issue below that seems
to answer the question at least for Jason's example:

   https://github.com/itanium-cxx-abi/cxx-abi/issues/64

But this is an open issue that leaves some other questions
unanswered, mainly that of the exact encoding of the literal
(the length of the directly encoded subsequence and the hash
algorithm to compute the hash value of the string).

In any event, using the same encoding as for initializer
lists (i.e., (elt-type, elt-value)...) doesn't follow this
approach.

Should I prototype the solution outlined in the issue for
GCC 9?

I suppose there's still the question of compatibility between
initializer lists and string literals, namely whether this

   B<A{"123"}>

is supposed to mangle the same as

   B<A{'1', '2', '3', 0}>

The ABI issue only talks about string literals and not braced
initializer lists.  I see in Revision History [150204] Add
mangling for braced initializer lists, so presumably there
is a difference, but I can't find what it is.

Martin
Jason Merrill March 28, 2019, 5:45 p.m. UTC | #15
On 3/27/19 6:56 PM, Martin Sebor wrote:
> On 3/27/19 3:11 PM, Martin Sebor wrote:
>> On 3/27/19 4:44 AM, Jonathan Wakely wrote:
>>> On 21/03/19 15:03 -0400, Jason Merrill wrote:
>>>> On 3/20/19 6:06 PM, Marek Polacek wrote:
>>>>> On Wed, Mar 20, 2019 at 10:58:32PM +0100, Jakub Jelinek wrote:
>>>>>> On Wed, Mar 20, 2019 at 05:55:04PM -0400, Marek Polacek wrote:
>>>>>>> On Wed, Mar 20, 2019 at 04:56:33PM -0300, Alexandre Oliva wrote:
>>>>>>>> On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:
>>>>>>>>
>>>>>>>>> This test fails with
>>>>>>>>> pr88534.C:58:1: sorry, unimplemented: string literal in 
>>>>>>>>> function template signature
>>>>>>>>
>>>>>>>> Interesting...  gcc-8 rejected it with an error message 
>>>>>>>> rejecting the
>>>>>>>> template parameter, but my latest trunk build (dated Mar 13, 
>>>>>>>> r269641)
>>>>>>>> compiles it all right.  Was there a subsequent fix, maybe?  I 
>>>>>>>> didn't
>>>>>>>> realize it was supposed to be rejected.
>>>>>>>
>>>>>>> Ah, that problem only started with r269814, namely this hunk:
>>>>>>
>>>>>> Maybe this is done too early and should be postponed to 
>>>>>> genericization
>>>>>> (perhaps except for TREE_STATIC vars)?
>>>>>
>>>>> Or skip when DECL is template_parm_object_p.
>>>>
>>>> Or handle it in mangle.c.  I don't see any reason we shouldn't accept
>>>>
>>>> struct A
>>>> {
>>>>  char c[4];
>>>> };
>>>>
>>>> template <A a> struct B { };
>>>> B<A{"FOO"}> b;
>>>>
>>>> Probably we should use the same mangling whether the initializer for 
>>>> c was spelled as a string literal or list of integers.
>>>>
>>>> The thing we still don't want to allow is mangling the *address* of 
>>>> a string literal.
>>>
>>> Will that help PR 47488 as well?
>>
>> What I have (attached) accepts all three test cases from PR 47488
>> (comment #0, #1, #2, and #5) but with different mangling.
>>
>> The difference in the mangling of the function in the test case
>> in comment #0 is
>>
>>    Clang: _Z1gIiEDTcl1fcvT__ELA1_KcEEERKS0_
>>    GCC 9: _Z1gIiEDTcl1fcvT__ELKc0EEERKS0_
>>
>> I'm not very familiar with the C++ ABI mangling but from what
>> I can tell, Clang treats the type as a literal array of 1 const
>> char element (LA1_Kc) without actually encoding its value, while
>> with my patch GCC encodes it as a constant literal initializer
>> consisting of 1 null char (LKc0).  In other words, Clang would
>> mangle these two the same for the same T:
>>
>>    template < typename T >
>>    decltype (f (T(), "123")) g (const T&);
>>
>>    template < typename T >
>>    decltype (f (T(), "abc")) g (const T&);
>>
>> while GCC would mangle them differently.
>>
>> Which is correct?  Clang's seems correct in this case but would
>> it also be correct to mangle Jason's B<A{"FOO"}> the same as
>> B<A{"BAR"}>?
> 
> After some poking around I found the issue below that seems
> to answer the question at least for Jason's example:
> 
>    https://github.com/itanium-cxx-abi/cxx-abi/issues/64
> 
> But this is an open issue that leaves some other questions
> unanswered, mainly that of the exact encoding of the literal
> (the length of the directly encoded subsequence and the hash
> algorithm to compute the hash value of the string).
> 
> In any event, using the same encoding as for initializer
> lists (i.e., (elt-type, elt-value)...) doesn't follow this
> approach.
> 
> Should I prototype the solution outlined in the issue for
> GCC 9?

I think let's leave that for the future, and use the aggregate encoding 
for GCC 9.

> I suppose there's still the question of compatibility between
> initializer lists and string literals, namely whether this
> 
>    B<A{"123"}>
> 
> is supposed to mangle the same as
> 
>    B<A{'1', '2', '3', 0}>
> 
> The ABI issue only talks about string literals and not braced
> initializer lists.  I see in Revision History [150204] Add
> mangling for braced initializer lists, so presumably there
> is a difference, but I can't find what it is.

The issue for mangling template arguments of class type is

   https://github.com/itanium-cxx-abi/cxx-abi/issues/63

The mangling of braced-init-lists is

# type {expr-list}, conversion with braced-init-list argument
::= tl <type> <braced-expression>* E

# {expr-list}, braced-init-list in any other context
::= il <braced-expression>* E

Your patch doesn't use this mangling.  Here's a variant of my example 
that actually causes these to show up in the mangling:

struct A { char c[4]; };
template <A a> struct B { };
void f(B<A{"FOO"}>) {}
void g(B<A{'F', 'O', 'O', '\0'}>) {}

Jason
Martin Sebor March 28, 2019, 11:54 p.m. UTC | #16
On 3/28/19 11:45 AM, Jason Merrill wrote:
> On 3/27/19 6:56 PM, Martin Sebor wrote:
>> On 3/27/19 3:11 PM, Martin Sebor wrote:
>>> On 3/27/19 4:44 AM, Jonathan Wakely wrote:
>>>> On 21/03/19 15:03 -0400, Jason Merrill wrote:
>>>>> On 3/20/19 6:06 PM, Marek Polacek wrote:
>>>>>> On Wed, Mar 20, 2019 at 10:58:32PM +0100, Jakub Jelinek wrote:
>>>>>>> On Wed, Mar 20, 2019 at 05:55:04PM -0400, Marek Polacek wrote:
>>>>>>>> On Wed, Mar 20, 2019 at 04:56:33PM -0300, Alexandre Oliva wrote:
>>>>>>>>> On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:
>>>>>>>>>
>>>>>>>>>> This test fails with
>>>>>>>>>> pr88534.C:58:1: sorry, unimplemented: string literal in 
>>>>>>>>>> function template signature
>>>>>>>>>
>>>>>>>>> Interesting...  gcc-8 rejected it with an error message 
>>>>>>>>> rejecting the
>>>>>>>>> template parameter, but my latest trunk build (dated Mar 13, 
>>>>>>>>> r269641)
>>>>>>>>> compiles it all right.  Was there a subsequent fix, maybe?  I 
>>>>>>>>> didn't
>>>>>>>>> realize it was supposed to be rejected.
>>>>>>>>
>>>>>>>> Ah, that problem only started with r269814, namely this hunk:
>>>>>>>
>>>>>>> Maybe this is done too early and should be postponed to 
>>>>>>> genericization
>>>>>>> (perhaps except for TREE_STATIC vars)?
>>>>>>
>>>>>> Or skip when DECL is template_parm_object_p.
>>>>>
>>>>> Or handle it in mangle.c.  I don't see any reason we shouldn't accept
>>>>>
>>>>> struct A
>>>>> {
>>>>>  char c[4];
>>>>> };
>>>>>
>>>>> template <A a> struct B { };
>>>>> B<A{"FOO"}> b;
>>>>>
>>>>> Probably we should use the same mangling whether the initializer 
>>>>> for c was spelled as a string literal or list of integers.
>>>>>
>>>>> The thing we still don't want to allow is mangling the *address* of 
>>>>> a string literal.
>>>>
>>>> Will that help PR 47488 as well?
>>>
>>> What I have (attached) accepts all three test cases from PR 47488
>>> (comment #0, #1, #2, and #5) but with different mangling.
>>>
>>> The difference in the mangling of the function in the test case
>>> in comment #0 is
>>>
>>>    Clang: _Z1gIiEDTcl1fcvT__ELA1_KcEEERKS0_
>>>    GCC 9: _Z1gIiEDTcl1fcvT__ELKc0EEERKS0_
>>>
>>> I'm not very familiar with the C++ ABI mangling but from what
>>> I can tell, Clang treats the type as a literal array of 1 const
>>> char element (LA1_Kc) without actually encoding its value, while
>>> with my patch GCC encodes it as a constant literal initializer
>>> consisting of 1 null char (LKc0).  In other words, Clang would
>>> mangle these two the same for the same T:
>>>
>>>    template < typename T >
>>>    decltype (f (T(), "123")) g (const T&);
>>>
>>>    template < typename T >
>>>    decltype (f (T(), "abc")) g (const T&);
>>>
>>> while GCC would mangle them differently.
>>>
>>> Which is correct?  Clang's seems correct in this case but would
>>> it also be correct to mangle Jason's B<A{"FOO"}> the same as
>>> B<A{"BAR"}>?
>>
>> After some poking around I found the issue below that seems
>> to answer the question at least for Jason's example:
>>
>>    https://github.com/itanium-cxx-abi/cxx-abi/issues/64
>>
>> But this is an open issue that leaves some other questions
>> unanswered, mainly that of the exact encoding of the literal
>> (the length of the directly encoded subsequence and the hash
>> algorithm to compute the hash value of the string).
>>
>> In any event, using the same encoding as for initializer
>> lists (i.e., (elt-type, elt-value)...) doesn't follow this
>> approach.
>>
>> Should I prototype the solution outlined in the issue for
>> GCC 9?
> 
> I think let's leave that for the future, and use the aggregate encoding 
> for GCC 9.
> 
>> I suppose there's still the question of compatibility between
>> initializer lists and string literals, namely whether this
>>
>>    B<A{"123"}>
>>
>> is supposed to mangle the same as
>>
>>    B<A{'1', '2', '3', 0}>
>>
>> The ABI issue only talks about string literals and not braced
>> initializer lists.  I see in Revision History [150204] Add
>> mangling for braced initializer lists, so presumably there
>> is a difference, but I can't find what it is.
> 
> The issue for mangling template arguments of class type is
> 
>    https://github.com/itanium-cxx-abi/cxx-abi/issues/63

Whoops.  Off-by-one error.  Thanks!

> 
> The mangling of braced-init-lists is
> 
> # type {expr-list}, conversion with braced-init-list argument
> ::= tl <type> <braced-expression>* E
> 
> # {expr-list}, braced-init-list in any other context
> ::= il <braced-expression>* E
> 
> Your patch doesn't use this mangling.  Here's a variant of my example 
> that actually causes these to show up in the mangling:
> 
> struct A { char c[4]; };
> template <A a> struct B { };
> void f(B<A{"FOO"}>) {}
> void g(B<A{'F', 'O', 'O', '\0'}>) {}

Right, that's also what I'm testing.  There are few interesting
variations.  Given

   struct A { char c[5]; };

all of these are equivalent and so should mangle the same:

   void f (B<A{"a\0b"}>) {}
   void f (B<A{"a\0b\0"}>) {}
   void f (B<A{ {'a', 0, 'b'}>) {}
   void f (B<A{ {'a', 0, 'b', 0}>) {}
   void f (B<A{ {'a', 0, 'b', 0, 0}>) {}

Interior nuls need to be mangled but the trailing ones, either
explicit or implicit, don't.  That also needs to be specified
in the ABI.

I believe we also need to handle these the same, both during
overloading and mangling:

   void f (B<A{ }>) {}
   void f (B<A{ 0 }>) {}
   void f (B<A{ 0, 0 }>) {}
   void f (B<A{ "" }>) {}

GCC currently treats them as distinct irrespective of A's member's
type.  I opened bug 89878 for this since I don't expect to deal
with the overloading part in this patch.

Martin
Jason Merrill March 29, 2019, 3:02 p.m. UTC | #17
On 3/28/19 7:54 PM, Martin Sebor wrote:
> On 3/28/19 11:45 AM, Jason Merrill wrote:
>> On 3/27/19 6:56 PM, Martin Sebor wrote:
>>> On 3/27/19 3:11 PM, Martin Sebor wrote:
>>>> On 3/27/19 4:44 AM, Jonathan Wakely wrote:
>>>>> On 21/03/19 15:03 -0400, Jason Merrill wrote:
>>>>>> On 3/20/19 6:06 PM, Marek Polacek wrote:
>>>>>>> On Wed, Mar 20, 2019 at 10:58:32PM +0100, Jakub Jelinek wrote:
>>>>>>>> On Wed, Mar 20, 2019 at 05:55:04PM -0400, Marek Polacek wrote:
>>>>>>>>> On Wed, Mar 20, 2019 at 04:56:33PM -0300, Alexandre Oliva wrote:
>>>>>>>>>> On Mar 20, 2019, Marek Polacek <polacek@redhat.com> wrote:
>>>>>>>>>>
>>>>>>>>>>> This test fails with
>>>>>>>>>>> pr88534.C:58:1: sorry, unimplemented: string literal in 
>>>>>>>>>>> function template signature
>>>>>>>>>>
>>>>>>>>>> Interesting...  gcc-8 rejected it with an error message 
>>>>>>>>>> rejecting the
>>>>>>>>>> template parameter, but my latest trunk build (dated Mar 13, 
>>>>>>>>>> r269641)
>>>>>>>>>> compiles it all right.  Was there a subsequent fix, maybe?  I 
>>>>>>>>>> didn't
>>>>>>>>>> realize it was supposed to be rejected.
>>>>>>>>>
>>>>>>>>> Ah, that problem only started with r269814, namely this hunk:
>>>>>>>>
>>>>>>>> Maybe this is done too early and should be postponed to 
>>>>>>>> genericization
>>>>>>>> (perhaps except for TREE_STATIC vars)?
>>>>>>>
>>>>>>> Or skip when DECL is template_parm_object_p.
>>>>>>
>>>>>> Or handle it in mangle.c.  I don't see any reason we shouldn't accept
>>>>>>
>>>>>> struct A
>>>>>> {
>>>>>>  char c[4];
>>>>>> };
>>>>>>
>>>>>> template <A a> struct B { };
>>>>>> B<A{"FOO"}> b;
>>>>>>
>>>>>> Probably we should use the same mangling whether the initializer 
>>>>>> for c was spelled as a string literal or list of integers.
>>>>>>
>>>>>> The thing we still don't want to allow is mangling the *address* 
>>>>>> of a string literal.
>>>>>
>>>>> Will that help PR 47488 as well?
>>>>
>>>> What I have (attached) accepts all three test cases from PR 47488
>>>> (comment #0, #1, #2, and #5) but with different mangling.
>>>>
>>>> The difference in the mangling of the function in the test case
>>>> in comment #0 is
>>>>
>>>>    Clang: _Z1gIiEDTcl1fcvT__ELA1_KcEEERKS0_
>>>>    GCC 9: _Z1gIiEDTcl1fcvT__ELKc0EEERKS0_
>>>>
>>>> I'm not very familiar with the C++ ABI mangling but from what
>>>> I can tell, Clang treats the type as a literal array of 1 const
>>>> char element (LA1_Kc) without actually encoding its value, while
>>>> with my patch GCC encodes it as a constant literal initializer
>>>> consisting of 1 null char (LKc0).  In other words, Clang would
>>>> mangle these two the same for the same T:
>>>>
>>>>    template < typename T >
>>>>    decltype (f (T(), "123")) g (const T&);
>>>>
>>>>    template < typename T >
>>>>    decltype (f (T(), "abc")) g (const T&);
>>>>
>>>> while GCC would mangle them differently.
>>>>
>>>> Which is correct?  Clang's seems correct in this case but would
>>>> it also be correct to mangle Jason's B<A{"FOO"}> the same as
>>>> B<A{"BAR"}>?
>>>
>>> After some poking around I found the issue below that seems
>>> to answer the question at least for Jason's example:
>>>
>>>    https://github.com/itanium-cxx-abi/cxx-abi/issues/64
>>>
>>> But this is an open issue that leaves some other questions
>>> unanswered, mainly that of the exact encoding of the literal
>>> (the length of the directly encoded subsequence and the hash
>>> algorithm to compute the hash value of the string).
>>>
>>> In any event, using the same encoding as for initializer
>>> lists (i.e., (elt-type, elt-value)...) doesn't follow this
>>> approach.
>>>
>>> Should I prototype the solution outlined in the issue for
>>> GCC 9?
>>
>> I think let's leave that for the future, and use the aggregate 
>> encoding for GCC 9.
>>
>>> I suppose there's still the question of compatibility between
>>> initializer lists and string literals, namely whether this
>>>
>>>    B<A{"123"}>
>>>
>>> is supposed to mangle the same as
>>>
>>>    B<A{'1', '2', '3', 0}>
>>>
>>> The ABI issue only talks about string literals and not braced
>>> initializer lists.  I see in Revision History [150204] Add
>>> mangling for braced initializer lists, so presumably there
>>> is a difference, but I can't find what it is.
>>
>> The issue for mangling template arguments of class type is
>>
>>    https://github.com/itanium-cxx-abi/cxx-abi/issues/63
> 
> Whoops.  Off-by-one error.  Thanks!
> 
>>
>> The mangling of braced-init-lists is
>>
>> # type {expr-list}, conversion with braced-init-list argument
>> ::= tl <type> <braced-expression>* E
>>
>> # {expr-list}, braced-init-list in any other context
>> ::= il <braced-expression>* E
>>
>> Your patch doesn't use this mangling.  Here's a variant of my example 
>> that actually causes these to show up in the mangling:
>>
>> struct A { char c[4]; };
>> template <A a> struct B { };
>> void f(B<A{"FOO"}>) {}
>> void g(B<A{'F', 'O', 'O', '\0'}>) {}
> 
> Right, that's also what I'm testing.  There are few interesting
> variations.  Given
> 
>    struct A { char c[5]; };
> 
> all of these are equivalent and so should mangle the same:
> 
>    void f (B<A{"a\0b"}>) {}
>    void f (B<A{"a\0b\0"}>) {}
>    void f (B<A{ {'a', 0, 'b'}>) {}
>    void f (B<A{ {'a', 0, 'b', 0}>) {}
>    void f (B<A{ {'a', 0, 'b', 0, 0}>) {}
> 
> Interior nuls need to be mangled but the trailing ones, either
> explicit or implicit, don't.  That also needs to be specified
> in the ABI.

Agreed, good thought.

> I believe we also need to handle these the same, both during
> overloading and mangling:
> 
>    void f (B<A{ }>) {}
>    void f (B<A{ 0 }>) {}
>    void f (B<A{ 0, 0 }>) {}
>    void f (B<A{ "" }>) {}

Indeed.

> GCC currently treats them as distinct irrespective of A's member's
> type.  I opened bug 89878 for this since I don't expect to deal
> with the overloading part in this patch.

Thanks.

Jason
diff mbox series

Patch

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 8305555681447..478d9b9b289b1 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -13601,6 +13601,13 @@  generic_parameter_die (tree parm, tree arg,
   dw_die_ref tmpl_die = NULL;
   const char *name = NULL;
 
+  /* C++2a accepts class literals as template parameters, and var
+     decls with initializers represent them.  The VAR_DECLs would be
+     rejected, but we can take the DECL_INITIAL constructor and
+     attempt to expand it.  */
+  if (TREE_CODE (arg) == VAR_DECL)
+    arg = DECL_INITIAL (arg);
+
   if (!parm || !DECL_NAME (parm) || !arg)
     return NULL;
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/pr88534.C b/gcc/testsuite/g++.dg/cpp2a/pr88534.C
new file mode 100644
index 0000000000000..54faf385f11aa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/pr88534.C
@@ -0,0 +1,65 @@ 
+// { dg-do compile { target c++2a } }
+// { dg-options "-g" }
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std
+{
+
+template <typename T, T... I>
+struct integer_sequence
+{
+  typedef T value_type;
+  static constexpr size_t size () noexcept { return sizeof...(I); }
+};
+
+template <typename T, T N>
+using make_integer_sequence = integer_sequence<T, __integer_pack (N)...>;
+
+template <size_t... I>
+using index_sequence = integer_sequence<size_t, I...>;
+
+template <size_t N>
+using make_index_sequence = make_integer_sequence<size_t, N>;
+}
+
+template <typename T, size_t N> struct S
+{
+  T content[N];
+  using char_type = T;
+  template <size_t... I>
+  constexpr S (const T (&input)[N], std::index_sequence<I...>) noexcept : content{input[I]...} { }
+  constexpr S (const T (&input)[N]) noexcept : S (input, std::make_index_sequence<N> ()) { }
+  constexpr size_t size () const noexcept
+  {
+    if (content[N - 1] == '\0')
+      return N - 1;
+    else
+      return N;
+  }
+  constexpr T operator[] (size_t i) const noexcept
+  {
+    return content[i];
+  }
+  constexpr const T *begin () const noexcept
+  {
+    return content;
+  }
+  constexpr const T *end () const noexcept
+  {
+    return content + size ();
+  }
+};
+
+template <typename T, size_t N> S (const T (&)[N]) -> S<T, N>;
+
+template <S S>
+struct F
+{
+};
+
+auto
+foo ()
+{
+  F<"test"> f;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/pr88537.C b/gcc/testsuite/g++.dg/cpp2a/pr88537.C
new file mode 100644
index 0000000000000..d558d45f57830
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/pr88537.C
@@ -0,0 +1,16 @@ 
+// { dg-do compile { target c++2a } }
+// { dg-options "-g" }
+
+struct pair {
+	unsigned a;
+	unsigned b;
+	constexpr pair(unsigned _a, unsigned _b) noexcept: a{_a}, b{_b} { }
+};
+
+template <pair p> void fnc() {
+	
+}
+
+void f() {
+    fnc<pair(10,20)>();
+}