Message ID | or8sxhkybq.fsf@lxoliva.fsfla.org |
---|---|
State | New |
Headers | show |
Series | [C++,debug,PR88534] accept VAR_DECL in class literal template parms | expand |
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
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
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)>(); +}
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
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.
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
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
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
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
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?
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
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
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:
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
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
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
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 --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)>(); +}