Implementing the UDL changes was pretty straightforward; I simplified cp_parser_userdef_string_literal using the releasing_vec type from mangle.c.
While looking at this, I realized that the string UDL template taking a character pack that we implemented for C++14 didn't actually make it into C++14, so I've added a pedwarn for it and no longer suggest it in the diagnostic about an invalid UDL template. * cp-tree.h (struct releasing_vec): Move from mangle.c. Add get_ref method. * parser.c (cp_parser_userdef_string_literal): Use it. Handle passing the string to a single template parameter of class type. (cp_parser_template_declaration_after_parameters): Allow it. Pedwarn about the character pack template that was proposed but not accepted for C++14, and don't suggest it. --- gcc/cp/cp-tree.h | 28 ++++++++ gcc/cp/mangle.c | 24 ------- gcc/cp/parser.c | 70 ++++++++++++------- gcc/testsuite/g++.dg/cpp0x/udlit-overflow.C | 36 +++++----- gcc/testsuite/g++.dg/cpp1y/pr58708.C | 1 + gcc/testsuite/g++.dg/cpp1y/pr59867.C | 1 + .../g++.dg/cpp1y/udlit-char-template-sfinae.C | 1 + ...it-char-template-vs-std-literal-operator.C | 1 + .../g++.dg/cpp1y/udlit-char-template.C | 1 + .../g++.dg/cpp1y/udlit-char-template2.C | 1 + gcc/testsuite/g++.dg/cpp2a/nontype-class6.C | 17 +++++ gcc/cp/ChangeLog | 9 +++ 12 files changed, 121 insertions(+), 69 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class6.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 61b431e5f9d..a895d0042ab 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -871,6 +871,34 @@ struct named_decl_hash : ggc_remove <tree> static void mark_deleted (value_type) { gcc_unreachable (); } }; +/* Simplified unique_ptr clone to release a tree vec on exit. */ + +struct releasing_vec +{ + typedef vec<tree, va_gc> vec_t; + + releasing_vec (vec_t *v): v(v) { } + releasing_vec (): v(make_tree_vector ()) { } + + /* Copy ops are deliberately declared but not defined, + copies must always be elided. */ + releasing_vec (const releasing_vec &); + releasing_vec &operator= (const releasing_vec &); + + vec_t &operator* () const { return *v; } + vec_t *operator-> () const { return v; } + vec_t *get() const { return v; } + operator vec_t *() const { return v; } + tree& operator[] (unsigned i) const { return (*v)[i]; } + + /* Necessary for use with vec** and vec*& interfaces. */ + vec_t *&get_ref () { return v; } + + ~releasing_vec() { release_tree_vector (v); } +private: + vec_t *v; +}; + struct GTY(()) tree_template_decl { struct tree_decl_common common; tree arguments; diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 1b323015ded..b9d8ee20116 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1545,30 +1545,6 @@ write_abi_tags (tree tags) release_tree_vector (vec); } -/* Simplified unique_ptr clone to release a tree vec on exit. */ - -struct releasing_vec -{ - typedef vec<tree, va_gc> vec_t; - - releasing_vec (vec_t *v): v(v) { } - releasing_vec (): v(make_tree_vector ()) { } - - /* Copy constructor is deliberately declared but not defined, - copies must always be elided. */ - releasing_vec (const releasing_vec &); - - vec_t &operator* () const { return *v; } - vec_t *operator-> () const { return v; } - vec_t *get () const { return v; } - operator vec_t *() const { return v; } - tree& operator[] (unsigned i) const { return (*v)[i]; } - - ~releasing_vec() { release_tree_vector (v); } -private: - vec_t *v; -}; - /* True iff the TREE_LISTS T1 and T2 of ABI tags are equivalent. */ static bool diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 5ea8e8ca012..30a47662f55 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -4565,40 +4565,47 @@ cp_parser_userdef_string_literal (tree literal) tree value = USERDEF_LITERAL_VALUE (literal); int len = TREE_STRING_LENGTH (value) / TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (value)))) - 1; - tree decl, result; - vec<tree, va_gc> *args; + tree decl; /* Build up a call to the user-defined operator. */ /* Lookup the name we got back from the id-expression. */ - args = make_tree_vector (); + releasing_vec rargs; + vec<tree, va_gc> *&args = rargs.get_ref(); vec_safe_push (args, value); vec_safe_push (args, build_int_cst (size_type_node, len)); decl = lookup_literal_operator (name, args); if (decl && decl != error_mark_node) - { - result = finish_call_expr (decl, &args, false, true, - tf_warning_or_error); - release_tree_vector (args); - return result; - } - release_tree_vector (args); + return finish_call_expr (decl, &args, false, true, + tf_warning_or_error); - /* Look for a template function with typename parameter CharT - and parameter pack CharT... Call the function with - template parameter characters representing the string. */ - args = make_tree_vector (); + /* Look for a suitable template function, either (C++20) with a single + parameter of class type, or (N3599) with typename parameter CharT and + parameter pack CharT... */ + args->truncate (0); decl = lookup_literal_operator (name, args); if (decl && decl != error_mark_node) { - tree tmpl_args = make_string_pack (value); + /* Use resolve_nondeduced_context to try to choose one form of template + or the other. */ + tree tmpl_args = make_tree_vec (1); + TREE_VEC_ELT (tmpl_args, 0) = value; decl = lookup_template_function (decl, tmpl_args); - result = finish_call_expr (decl, &args, false, true, - tf_warning_or_error); - release_tree_vector (args); - return result; + tree res = resolve_nondeduced_context (decl, tf_none); + if (DECL_P (res)) + decl = res; + else + { + TREE_OPERAND (decl, 1) = make_string_pack (value); + res = resolve_nondeduced_context (decl, tf_none); + if (DECL_P (res)) + decl = res; + } + if (!DECL_P (decl) && cxx_dialect > cxx17) + TREE_OPERAND (decl, 1) = tmpl_args; + return finish_call_expr (decl, &args, false, true, + tf_warning_or_error); } - release_tree_vector (args); error ("unable to find string literal operator %qD with %qT, %qT arguments", name, TREE_TYPE (value), size_type_node); @@ -27222,8 +27229,12 @@ cp_parser_template_declaration_after_parameters (cp_parser* parser, { tree parm_list = TREE_VEC_ELT (parameter_list, 0); tree parm = INNERMOST_TEMPLATE_PARMS (parm_list); - if (TREE_TYPE (parm) != char_type_node - || !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))) + if (CLASS_TYPE_P (TREE_TYPE (parm))) + /* OK, C++20 string literal operator template. We don't need + to warn in lower dialects here because we will have already + warned about the template parameter. */; + else if (TREE_TYPE (parm) != char_type_node + || !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))) ok = false; } else if (num_parms == 2 && cxx_dialect >= cxx14) @@ -27236,20 +27247,25 @@ cp_parser_template_declaration_after_parameters (cp_parser* parser, || TREE_TYPE (parm) != TREE_TYPE (type) || !TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm))) ok = false; + else + /* http://cplusplus.github.io/EWG/ewg-active.html#66 */ + pedwarn (DECL_SOURCE_LOCATION (decl), OPT_Wpedantic, + "ISO C++ did not adopt string literal operator templa" + "tes taking an argument pack of characters"); } else ok = false; } if (!ok) { - if (cxx_dialect >= cxx14) - error ("literal operator template %qD has invalid parameter list." - " Expected non-type template argument pack <char...>" - " or <typename CharT, CharT...>", + if (cxx_dialect > cxx17) + error ("literal operator template %qD has invalid parameter list;" + " Expected non-type template parameter pack <char...> " + " or single non-type parameter of class type", decl); else error ("literal operator template %qD has invalid parameter list." - " Expected non-type template argument pack <char...>", + " Expected non-type template parameter pack <char...>", decl); } } diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-overflow.C b/gcc/testsuite/g++.dg/cpp0x/udlit-overflow.C index 057978c3275..1b9888b7159 100644 --- a/gcc/testsuite/g++.dg/cpp0x/udlit-overflow.C +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-overflow.C @@ -1,19 +1,19 @@ // { dg-do compile { target c++11 } } -// PR c++/52654 - -int -operator"" _w(const char*) -{ return 0; } - -template<char...> - int - operator"" _tw() - { return 0; } - -int i = 12345678901234567890123456789012345678901234567890_w; -int j = 12345678901234567890123456789.012345678901234567890e+1234567890_w; -int k = 12345678901234567890123456789.012345678901234567890e-1234567890_w; - -int ti = 12345678901234567890123456789012345678901234567890_tw; -int tj = 12345678901234567890123456789.012345678901234567890e+1234567890_tw; -int tk = 12345678901234567890123456789.012345678901234567890e-1234567890_tw; +// PR c++/52654 + +int +operator"" _w(const char*) +{ return 0; } + +template<char...> + int + operator"" _tw() + { return 0; } + +int i = 12345678901234567890123456789012345678901234567890_w; +int j = 12345678901234567890123456789.012345678901234567890e+1234567890_w; +int k = 12345678901234567890123456789.012345678901234567890e-1234567890_w; + +int ti = 12345678901234567890123456789012345678901234567890_tw; +int tj = 12345678901234567890123456789.012345678901234567890e+1234567890_tw; +int tk = 12345678901234567890123456789.012345678901234567890e-1234567890_tw; diff --git a/gcc/testsuite/g++.dg/cpp1y/pr58708.C b/gcc/testsuite/g++.dg/cpp1y/pr58708.C index b46e54bbca3..f1fc3b46227 100644 --- a/gcc/testsuite/g++.dg/cpp1y/pr58708.C +++ b/gcc/testsuite/g++.dg/cpp1y/pr58708.C @@ -1,4 +1,5 @@ // { dg-do run { target c++14 } } +// { dg-options -w } template<typename, typename> struct is_same diff --git a/gcc/testsuite/g++.dg/cpp1y/pr59867.C b/gcc/testsuite/g++.dg/cpp1y/pr59867.C index 2c4f1d046bf..ee468aabb2b 100644 --- a/gcc/testsuite/g++.dg/cpp1y/pr59867.C +++ b/gcc/testsuite/g++.dg/cpp1y/pr59867.C @@ -1,5 +1,6 @@ // PR c++/59867 // { dg-do compile { target c++14 } } +// { dg-options -w } using namespace std; diff --git a/gcc/testsuite/g++.dg/cpp1y/udlit-char-template-sfinae.C b/gcc/testsuite/g++.dg/cpp1y/udlit-char-template-sfinae.C index a9c577fd110..b523858e9c0 100644 --- a/gcc/testsuite/g++.dg/cpp1y/udlit-char-template-sfinae.C +++ b/gcc/testsuite/g++.dg/cpp1y/udlit-char-template-sfinae.C @@ -1,4 +1,5 @@ // { dg-do run { target c++14 } } +// { dg-options -w } #include <cassert> diff --git a/gcc/testsuite/g++.dg/cpp1y/udlit-char-template-vs-std-literal-operator.C b/gcc/testsuite/g++.dg/cpp1y/udlit-char-template-vs-std-literal-operator.C index 6e3ffe4ecd3..c5a67c96cf6 100644 --- a/gcc/testsuite/g++.dg/cpp1y/udlit-char-template-vs-std-literal-operator.C +++ b/gcc/testsuite/g++.dg/cpp1y/udlit-char-template-vs-std-literal-operator.C @@ -1,4 +1,5 @@ // { dg-do run { target c++14 } } +// { dg-options -w } #include <cassert> diff --git a/gcc/testsuite/g++.dg/cpp1y/udlit-char-template.C b/gcc/testsuite/g++.dg/cpp1y/udlit-char-template.C index 989b9babd1f..6b7b5ecec6f 100644 --- a/gcc/testsuite/g++.dg/cpp1y/udlit-char-template.C +++ b/gcc/testsuite/g++.dg/cpp1y/udlit-char-template.C @@ -1,4 +1,5 @@ // { dg-do compile { target c++14 } } +// { dg-options -w } template<typename CharT, CharT... String> int diff --git a/gcc/testsuite/g++.dg/cpp1y/udlit-char-template2.C b/gcc/testsuite/g++.dg/cpp1y/udlit-char-template2.C index 06c13261156..d3c4c67ea26 100644 --- a/gcc/testsuite/g++.dg/cpp1y/udlit-char-template2.C +++ b/gcc/testsuite/g++.dg/cpp1y/udlit-char-template2.C @@ -1,5 +1,6 @@ // PR c++/85864 // { dg-do compile { target c++14 } } +// { dg-options -w } template<class T, T... S> struct String_template {}; diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class6.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class6.C new file mode 100644 index 00000000000..246fab6c178 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class6.C @@ -0,0 +1,17 @@ +// { dg-do compile { target c++2a } } + +struct A { + char ar[10]; + constexpr A (const char *p) : ar() + { + for (int i = 0; i < 10; ++i) + if ((ar[i] = p[i]) == 0) + break; + } + // auto operator<=> (const A&) = default; +}; + +template <A a> constexpr A operator "" _sh() { return a; } + +constexpr auto a = "foo"_sh; +static_assert (a.ar[0] == 'f'); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 95149b19656..b0dc668d9df 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,14 @@ 2018-11-04 Jason Merrill <ja...@redhat.com> + Implement UDL changes from P0732R2. + * cp-tree.h (struct releasing_vec): Move from mangle.c. + Add get_ref method. + * parser.c (cp_parser_userdef_string_literal): Use it. Handle + passing the string to a single template parameter of class type. + (cp_parser_template_declaration_after_parameters): Allow it. + Pedwarn about the character pack template that was proposed but not + accepted for C++14, and don't suggest it. + Implement P0732R2, class types in non-type template parameters. * error.c (dump_simple_decl): Look through a template parm object. * mangle.c (write_template_arg): Likewise. -- 2.17.2