Message ID | 20190107235642.GI28316@redhat.com |
---|---|
State | New |
Headers | show |
Series | C++ PATCH for c++/88538 - braced-init-list in template-argument-list | expand |
On 1/7/19 6:56 PM, Marek Polacek wrote: > At the risk of seeming overly eager, I thought it would be reasonable to > go with the following: enabling braced-init-list as a template-argument. > As the discussion on the reflector clearly indicates, this was the intent > from the get-go. > > I know, it's not a regression. But I restricted the change to C++20, and it > should strictly allow code that wasn't accepted before -- when a template > argument starts with {. Perhaps we could even drop the C++20 check. > > What's your preference? Let's keep the C++20 check for now at least. I'd suggest moving the change further down, with this code: > if (cxx_dialect <= cxx14) > argument = cp_parser_constant_expression (parser); > else > { > /* With C++17 generalized non-type template arguments we need to handle > lvalue constant expressions, too. */ > argument = cp_parser_assignment_expression (parser); > require_potential_constant_expression (argument); > } Jason
On Mon, Jan 07, 2019 at 09:52:55PM -0500, Jason Merrill wrote: > On 1/7/19 6:56 PM, Marek Polacek wrote: > > At the risk of seeming overly eager, I thought it would be reasonable to > > go with the following: enabling braced-init-list as a template-argument. > > As the discussion on the reflector clearly indicates, this was the intent > > from the get-go. > > > > I know, it's not a regression. But I restricted the change to C++20, and it > > should strictly allow code that wasn't accepted before -- when a template > > argument starts with {. Perhaps we could even drop the C++20 check. > > > > What's your preference? > > Let's keep the C++20 check for now at least. I'd suggest moving the change > further down, with this code: Okay. I've experimented with checking expr_non_constant_p, but this version gives better diagnostics. Bootstrapped/regtested running on x86_64-linux, ok for trunk if it passes? 2019-01-08 Marek Polacek <polacek@redhat.com> PR c++/88538 - braced-init-list in template-argument-list. * parser.c (cp_parser_template_argument): Handle braced-init-list when in C++20. * g++.dg/cpp2a/nontype-class11.C: New test. diff --git gcc/cp/parser.c gcc/cp/parser.c index bca1739ace3..87f37d8ab2b 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -17020,6 +17020,18 @@ cp_parser_template_argument (cp_parser* parser) argument = cp_parser_constant_expression (parser); else { + /* In C++20, we can encounter a braced-init-list. */ + if (cxx_dialect >= cxx2a + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + cp_parser_parse_tentatively (parser); + bool expr_non_constant_p; + argument = cp_parser_braced_list (parser, &expr_non_constant_p); + if (cp_parser_parse_definitely (parser)) + /* Yup, it was a braced-init-list. */ + return argument; + } + /* With C++17 generalized non-type template arguments we need to handle lvalue constant expressions, too. */ argument = cp_parser_assignment_expression (parser); diff --git gcc/testsuite/g++.dg/cpp2a/nontype-class11.C gcc/testsuite/g++.dg/cpp2a/nontype-class11.C new file mode 100644 index 00000000000..8a06d23904b --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/nontype-class11.C @@ -0,0 +1,21 @@ +// PR c++/88538 +// { dg-do compile { target c++2a } } + +struct S { + unsigned a; + unsigned b; + constexpr S(unsigned _a, unsigned _b) noexcept: a{_a}, b{_b} { } +}; + +template <S p> +void fnc() +{ +} + +template<S s> struct X { }; + +void f() +{ + fnc<{10,20}>(); + X<{1, 2}> x; +}
On 1/8/19 10:42 AM, Marek Polacek wrote: > On Mon, Jan 07, 2019 at 09:52:55PM -0500, Jason Merrill wrote: >> On 1/7/19 6:56 PM, Marek Polacek wrote: >>> At the risk of seeming overly eager, I thought it would be reasonable to >>> go with the following: enabling braced-init-list as a template-argument. >>> As the discussion on the reflector clearly indicates, this was the intent >>> from the get-go. >>> >>> I know, it's not a regression. But I restricted the change to C++20, and it >>> should strictly allow code that wasn't accepted before -- when a template >>> argument starts with {. Perhaps we could even drop the C++20 check. >>> >>> What's your preference? >> >> Let's keep the C++20 check for now at least. I'd suggest moving the change >> further down, with this code: > > Okay. I've experimented with checking expr_non_constant_p, but this version > gives better diagnostics. > > Bootstrapped/regtested running on x86_64-linux, ok for trunk if it passes? > > 2019-01-08 Marek Polacek <polacek@redhat.com> > > PR c++/88538 - braced-init-list in template-argument-list. > * parser.c (cp_parser_template_argument): Handle braced-init-list when > in C++20. > > * g++.dg/cpp2a/nontype-class11.C: New test. > > diff --git gcc/cp/parser.c gcc/cp/parser.c > index bca1739ace3..87f37d8ab2b 100644 > --- gcc/cp/parser.c > +++ gcc/cp/parser.c > @@ -17020,6 +17020,18 @@ cp_parser_template_argument (cp_parser* parser) > argument = cp_parser_constant_expression (parser); > else > { > + /* In C++20, we can encounter a braced-init-list. */ > + if (cxx_dialect >= cxx2a > + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) > + { > + cp_parser_parse_tentatively (parser); Hmm, I wonder if we would get better diagnostics for an ill-formed braced-init-list without tentative parsing here. OK either way. Jason
On Tue, Jan 08, 2019 at 03:45:54PM -0500, Jason Merrill wrote: > On 1/8/19 10:42 AM, Marek Polacek wrote: > > @@ -17020,6 +17020,18 @@ cp_parser_template_argument (cp_parser* parser) > > argument = cp_parser_constant_expression (parser); > > else > > { > > + /* In C++20, we can encounter a braced-init-list. */ > > + if (cxx_dialect >= cxx2a > > + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) > > + { > > + cp_parser_parse_tentatively (parser); > > Hmm, I wonder if we would get better diagnostics for an ill-formed > braced-init-list without tentative parsing here. OK either way. We get the same diagnostics with or without tentative parsing. But since we've checked that the next following token is {, I think it would be cleaner to just parse it for real. This is what I'm about to commit then. Thanks for the reviews! 2019-01-08 Marek Polacek <polacek@redhat.com> PR c++/88538 - braced-init-list in template-argument-list. * parser.c (cp_parser_template_argument): Handle braced-init-list when in C++20. * g++.dg/cpp2a/nontype-class11.C: New test. diff --git gcc/cp/parser.c gcc/cp/parser.c index ca75c010e22..f441943dc8e 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -17026,6 +17026,14 @@ cp_parser_template_argument (cp_parser* parser) argument = cp_parser_constant_expression (parser); else { + /* In C++20, we can encounter a braced-init-list. */ + if (cxx_dialect >= cxx2a + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + bool expr_non_constant_p; + return cp_parser_braced_list (parser, &expr_non_constant_p); + } + /* With C++17 generalized non-type template arguments we need to handle lvalue constant expressions, too. */ argument = cp_parser_assignment_expression (parser); diff --git gcc/testsuite/g++.dg/cpp2a/nontype-class11.C gcc/testsuite/g++.dg/cpp2a/nontype-class11.C new file mode 100644 index 00000000000..8a06d23904b --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/nontype-class11.C @@ -0,0 +1,21 @@ +// PR c++/88538 +// { dg-do compile { target c++2a } } + +struct S { + unsigned a; + unsigned b; + constexpr S(unsigned _a, unsigned _b) noexcept: a{_a}, b{_b} { } +}; + +template <S p> +void fnc() +{ +} + +template<S s> struct X { }; + +void f() +{ + fnc<{10,20}>(); + X<{1, 2}> x; +}
diff --git gcc/cp/parser.c gcc/cp/parser.c index bca1739ace3..7de2ee28b20 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -16892,7 +16892,18 @@ cp_parser_template_argument (cp_parser* parser) return argument; } /* It must be a non-type argument. In C++17 any constant-expression is - allowed. */ + allowed. In C++20, we can encounter a braced-init-list. */ + if (cxx_dialect >= cxx2a + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + cp_parser_parse_tentatively (parser); + bool expr_non_constant_p; + argument = cp_parser_braced_list (parser, &expr_non_constant_p); + if (cp_parser_parse_definitely (parser)) + /* Yup, it was a braced-init-list. */ + return argument; + } + if (cxx_dialect > cxx14) goto general_expr; diff --git gcc/testsuite/g++.dg/cpp2a/nontype-class11.C gcc/testsuite/g++.dg/cpp2a/nontype-class11.C new file mode 100644 index 00000000000..8a06d23904b --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/nontype-class11.C @@ -0,0 +1,21 @@ +// PR c++/88538 +// { dg-do compile { target c++2a } } + +struct S { + unsigned a; + unsigned b; + constexpr S(unsigned _a, unsigned _b) noexcept: a{_a}, b{_b} { } +}; + +template <S p> +void fnc() +{ +} + +template<S s> struct X { }; + +void f() +{ + fnc<{10,20}>(); + X<{1, 2}> x; +}