On 10/28/20 10:56 PM, Marek Polacek wrote:
On Wed, Oct 28, 2020 at 02:34:15PM -0400, Jason Merrill via Gcc-patches wrote:
On 10/28/20 2:02 PM, Marek Polacek wrote:
This patch implements CWG 625 which prohibits using auto in a template
argument.  A few tests used this construction.  We could perhaps only
give an error in C++20, but not in C++17 with -fconcepts.

We should not give an error with -fconcepts-ts, this was allowed by the
Concepts TS.

Ah, I see.  Presumably we should only get the errors on { target c++20 }.

...which won't happen in c++17_only tests, so no need to change auto[134].C.

Does just changing !flag_concepts to !flag_concepts_ts work?

Almost: one issue is that it would regress the error message for
something like

   using T = auto;

for which we have dedicated code in grokdeclarator, which is nicer than just
the terse "invalid use."  So I think if flag_concepts is on, we should still
check in_template_argument_list_p.  Since the logic has gotten a bit tricky,
I've introduced a new variable, rather than to play hard-to-read games with
?: in the if.

Thanks,

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
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/concepts/auto1.C: Add dg-error.
        * g++.dg/concepts/auto3.C: Likewise.
        * g++.dg/concepts/auto4.C: Likewise.
        * 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                                 | 15 +++++++++++++--
  gcc/testsuite/g++.dg/DRs/dr625.C                | 15 +++++++++++++++
  gcc/testsuite/g++.dg/concepts/auto1.C           |  4 ++--
  gcc/testsuite/g++.dg/concepts/auto3.C           |  6 +++---
  gcc/testsuite/g++.dg/concepts/auto4.C           |  2 +-
  gcc/testsuite/g++.dg/cpp0x/auto3.C              |  2 +-
  gcc/testsuite/g++.dg/cpp0x/auto9.C              |  2 +-
  gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C | 12 ++++++------
  gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C | 12 ++++++------
  gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C   |  2 +-
  10 files changed, 49 insertions(+), 23 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/DRs/dr625.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 234079559b9..6570b0af889 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -22417,9 +22417,17 @@ 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.  */

In this comment, please mention that we're only allowing it here for the better diagnostic. OK with this and dropping the unnecessary testsuite changes.

+  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))
@@ -22446,6 +22454,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
index 00000000000..ce30a9258e6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr625.C
@@ -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" }
+}
diff --git a/gcc/testsuite/g++.dg/concepts/auto1.C 
b/gcc/testsuite/g++.dg/concepts/auto1.C
index e05330610fc..86f3b8e0aec 100644
--- a/gcc/testsuite/g++.dg/concepts/auto1.C
+++ b/gcc/testsuite/g++.dg/concepts/auto1.C
@@ -7,8 +7,8 @@ A<int, int> a;
  A<double, float> a2;
  A<double, double> a22;
-A<auto, auto> b = a;
-A<auto, auto> b1 = a2;
+A<auto, auto> b = a;             // { dg-error "" "" { target c++20 } }
+A<auto, auto> b1 = a2;           // { dg-error "" "" { target c++20 } }
template <class T> concept bool C = __is_same_as (T, int); diff --git a/gcc/testsuite/g++.dg/concepts/auto3.C b/gcc/testsuite/g++.dg/concepts/auto3.C
index 27a6afa4ed9..7c021856910 100644
--- a/gcc/testsuite/g++.dg/concepts/auto3.C
+++ b/gcc/testsuite/g++.dg/concepts/auto3.C
@@ -4,10 +4,10 @@
  template <class...> class tuple {};
tuple<int> t;
-tuple<auto> y = t;
+tuple<auto> y = t;               // { dg-error "" "" { target c++20 } }
tuple<int,double> t2;
-tuple<auto...> x = t2;
-tuple<auto...> x2 = t;
+tuple<auto...> x = t2;           // { dg-error "" "" { target c++20 } }
+tuple<auto...> x2 = t;           // { dg-error "" "" { target c++20 } }
tuple<auto> y2 = t2; // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/concepts/auto4.C 
b/gcc/testsuite/g++.dg/concepts/auto4.C
index 8bf3fa9b1ce..2b0e774eac1 100644
--- a/gcc/testsuite/g++.dg/concepts/auto4.C
+++ b/gcc/testsuite/g++.dg/concepts/auto4.C
@@ -4,7 +4,7 @@
template<typename... Ts> struct A {}; -template<typename... Us> A<auto...> foo() { return A{}; }
+template<typename... Us> A<auto...> foo() { return A{}; }  // { dg-error "" "" 
{ target c++20 } }
void bar()
  {
diff --git a/gcc/testsuite/g++.dg/cpp0x/auto3.C 
b/gcc/testsuite/g++.dg/cpp0x/auto3.C
index 709898db39d..2cd0520023d 100644
--- a/gcc/testsuite/g++.dg/cpp0x/auto3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/auto3.C
@@ -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 } } } diff --git a/gcc/testsuite/g++.dg/cpp0x/auto9.C b/gcc/testsuite/g++.dg/cpp0x/auto9.C
index a3f9be521d6..0e80c30ef74 100644
--- a/gcc/testsuite/g++.dg/cpp0x/auto9.C
+++ b/gcc/testsuite/g++.dg/cpp0x/auto9.C
@@ -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 } 
} }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C
index ce69a0f8ac5..290aaf83819 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-2.C
@@ -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 {
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C
index 3809c2d3033..d612327b9ae 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979-3.C
@@ -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 {
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C
index 9bd40df103a..81555eb4554 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-pr84979.C
@@ -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" }
  }

base-commit: 323dd4255203479d8c456b85513db4f8e0041d04


Reply via email to