c++: Implement CWG 625: Use of auto as template-arg [PR97479]
authorMarek Polacek <polacek@redhat.com>
Mon, 26 Oct 2020 21:35:56 +0000 (17:35 -0400)
committerMarek Polacek <polacek@redhat.com>
Thu, 29 Oct 2020 21:35:56 +0000 (17:35 -0400)
This patch implements CWG 625 which prohibits using auto in a template
argument.  A few tests used this construction.  Since this usage was
allowed by the Concepts TS, we only give an error in C++20.

gcc/cp/ChangeLog:

DR 625
PR c++/97479
* parser.c (cp_parser_type_id_1): Reject using auto as
a template-argument in C++20.

gcc/testsuite/ChangeLog:

DR 625
PR c++/97479
* g++.dg/cpp0x/auto3.C: Update dg-error.
* g++.dg/cpp0x/auto9.C: Likewise.
* g++.dg/cpp2a/concepts-pr84979-2.C: Likewise.
* g++.dg/cpp2a/concepts-pr84979-3.C: Likewise.
* g++.dg/cpp2a/concepts-pr84979.C: Likewise.
* g++.dg/DRs/dr625.C: New test.

gcc/cp/parser.c
gcc/testsuite/g++.dg/DRs/dr625.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/auto3.C
gcc/testsuite/g++.dg/cpp0x/auto9.C
gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C
gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C
gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C

index d65b408a6f5bbc28b527fb3d254b185185e79064..bd8c241dd822407c86a3596d61204dc3220c330d 100644 (file)
@@ -22419,9 +22419,20 @@ cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags,
   if (!cp_parser_parse_definitely (parser))
     abstract_declarator = NULL;
 
+  bool auto_typeid_ok = false;
+  /* The concepts TS allows 'auto' as a type-id.  */
+  if (flag_concepts_ts)
+    auto_typeid_ok = !parser->in_type_id_in_expr_p;
+  /* DR 625 prohibits use of auto as a template-argument.  We allow 'auto'
+     outside the template-argument-list context here only for the sake of
+     diagnostic: grokdeclarator then can emit a better error message for
+     e.g. using T = auto.  */
+  else if (flag_concepts)
+    auto_typeid_ok = (!parser->in_type_id_in_expr_p
+                     && !parser->in_template_argument_list_p);
+
   if (type_specifier_seq.type
-      /* The concepts TS allows 'auto' as a type-id.  */
-      && (!flag_concepts || parser->in_type_id_in_expr_p)
+      && !auto_typeid_ok
       /* None of the valid uses of 'auto' in C++14 involve the type-id
         nonterminal, but it is valid in a trailing-return-type.  */
       && !(cxx_dialect >= cxx14 && is_trailing_return))
@@ -22448,6 +22459,9 @@ cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags,
                inform (DECL_SOURCE_LOCATION (tmpl), "%qD declared here",
                        tmpl);
              }
+           else if (parser->in_template_argument_list_p)
+             error_at (loc, "%qT not permitted in template argument",
+                       auto_node);
            else
              error_at (loc, "invalid use of %qT", auto_node);
            return error_mark_node;
diff --git a/gcc/testsuite/g++.dg/DRs/dr625.C b/gcc/testsuite/g++.dg/DRs/dr625.C
new file mode 100644 (file)
index 0000000..ce30a92
--- /dev/null
@@ -0,0 +1,15 @@
+// DR 625 - Use of auto as a template-argument
+// PR c++/97479
+// { dg-do compile { target c++14 } }
+
+template<typename>
+struct A { };
+
+void f(int);
+
+int main()
+{
+  A<decltype(auto)> x = A<void>(); // { dg-error "not permitted|invalid|cannot convert" }
+  A<auto> a = A<void>(); // { dg-error "not permitted|invalid|cannot convert" }
+  void (*p)(auto); // { dg-error "parameter" }
+}
index 709898db39db962c23cf2f3a80454e619bcb2a32..2cd0520023d712d2beeda39a693f67d1cdaf3305 100644 (file)
@@ -17,7 +17,7 @@ struct A { };
 
 A<int> A1;
 // CWG issue 625
-A<auto> A2 = A1;               // { dg-error "" "" { target { ! concepts } } }
+A<auto> A2 = A1;               // { dg-error "" }
 
 auto foo() { }                 // { dg-error "auto" "" { target { ! c++14 } } }
 
index a3f9be521d608b077440018f5e9b873f49a04a7e..0e80c30ef74fdfe655e25952e8a982569e17074e 100644 (file)
@@ -114,7 +114,7 @@ badthrow2 () throw (auto &)                 // { dg-error "invalid use of|expected" }
 template <auto V = 4> struct G {};             // { dg-error "11:parameter" "" { target { ! c++17 } } }
 
 template <typename T> struct H { H (); ~H (); };
-H<auto> h;                                     // { dg-error "invalid|initializer" }
+H<auto> h;                                     // { dg-error "invalid|initializer|not permitted in template argument" }
 
 void qq (auto);                       // { dg-error "auto" "" { target { ! concepts } } }
 void qr (auto*);              // { dg-error "auto" "" { target { ! concepts } } }
index ce69a0f8ac53169865de422d55d2a4536415c83f..290aaf83819cec9cc42bb21a32e73a370f21db61 100644 (file)
@@ -4,9 +4,9 @@
 template <typename T>
 void foo1(T& t) {
   typename T::template C<void> tcv = t;
-  typename T::template C<auto> u = tcv;
-  T::template C<auto>::f (tcv, u); // { dg-error "incomplete" }
-  (typename T::template D<auto> (t)); // { dg-error "invalid" }
+  typename T::template C<auto> u = tcv; // { dg-error "not permitted" "" { target c++20 } }
+  T::template C<auto>::f (tcv, u); // { dg-error "incomplete|not permitted" }
+  (typename T::template D<auto> (t)); // { dg-error "invalid|not permitted" }
 }
 
 struct T1 {
@@ -22,9 +22,9 @@ struct T1 {
 template <typename T>
 void foo2(T& t) {
   typename T::template C<void> tcv = t;
-  typename T::template C<auto> u = tcv;
-  T::template C<auto>::f (tcv, u); // { dg-error "incomplete" }
-  T::template D<auto> (t); // { dg-error "invalid" }
+  typename T::template C<auto> u = tcv; // { dg-error "not permitted" "" { target c++20 } }
+  T::template C<auto>::f (tcv, u); // { dg-error "incomplete|not permitted" }
+  T::template D<auto> (t); // { dg-error "invalid|not permitted" }
 }
 
 struct T2 {
index 3809c2d3033bacfc198762885e4983dadf5da642..d612327b9ae5d7c96563910c5afca5455d5934d0 100644 (file)
@@ -8,9 +8,9 @@
 template <typename T>
 void foo1(T& t) {
   typename T::template C<void> tcv = t;
-  typename T::template C<auto> u = tcv;
-  T::template C<auto>::f (tcv, u); // { dg-error "incomplete" }
-  (typename T::template D<auto> (t)); // { dg-error "invalid" }
+  typename T::template C<auto> u = tcv; // { dg-error "not permitted" "" { target c++20 } }
+  T::template C<auto>::f (tcv, u); // { dg-error "incomplete|not permitted" }
+  (typename T::template D<auto> (t)); // { dg-error "invalid|not permitted" }
 }
 
 struct T1 {
@@ -26,9 +26,9 @@ struct T1 {
 template <typename T>
 void foo2(T& t) {
   typename T::template C<void> tcv = t;
-  typename T::template C<auto> u = tcv;
-  T::template C<auto>::f (tcv, u); // { dg-error "incomplete" }
-  T::template D<auto> (t); // { dg-error "yields a type" }
+  typename T::template C<auto> u = tcv; // { dg-error "not permitted" "" { target c++20 } }
+  T::template C<auto>::f (tcv, u); // { dg-error "incomplete|not permitted" }
+  T::template D<auto> (t); // { dg-error "yields a type|not permitted" }
 }
 
 struct T2 {
index 9bd40df103a8812ee0b887c70f771ebf6aedbf78..81555eb455444de80c4a737d1e8f0f6ea38d86e0 100644 (file)
@@ -5,5 +5,5 @@ template<typename> void foo() {}
 
 void bar()
 {
-  foo<auto>(); // { dg-error "invalid" }
+  foo<auto>(); // { dg-error "not permitted|invalid|no matching function" }
 }