Bug 104113 - invalid template argument causes the type to become int which confuses the rest of the diagnostic
Summary: invalid template argument causes the type to become int which confuses the re...
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 12.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic, FIXME
: 114248 (view as bug list)
Depends on:
Blocks:
 
Reported: 2022-01-19 10:46 UTC by qingzhe huang
Modified: 2024-05-09 03:39 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2022-01-19 00:00:00


Attachments
cp_parser_simulate_error logic (429 bytes, patch)
2022-01-21 14:48 UTC, qingzhe huang
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description qingzhe huang 2022-01-19 10:46:26 UTC
DR 625 forbids "auto" to be used in template argument. And developer has specific error message for this and fails to issue it for the very case: (https://www.godbolt.org/z/198fn1jr1)

template <class T> struct A {};
template <class T> void f(A<T> x) {}

void g()
{
    f(A<short>());

    A<auto> x = A<short>();
}


The error message is very misleading. Note that only the 2nd error message is parser confirmed error message which is considered as conversion issue instead of "auto" being forbidden to be in template argument. (The 1st error message is parser tentative parsing issued.)

<source>: In function 'void g()':
<source>:14:11: error: template argument 1 is invalid
   14 |     A<auto> x = A<short>();
      |           ^
<source>:14:17: error: cannot convert 'A<short int>' to 'int' in initialization
   14 |     A<auto> x = A<short>();
      |                 ^~~~~~~~~~
      |                 |
      |                 A<short int>



And this case can be reduced as 

template<typename T>
struct A{};
A<auto> x = A<short>();

This is related to PR104091, however, it is very different because this one is not affected by "-std=c++XX"
Comment 1 Drea Pinski 2022-01-19 11:01:28 UTC
Auto has nothing to do with the problematic error message, take:
template<typename T>
struct A{};
A<tttt> x = A<short>();

GCC still produces:

<source>:4:13: error: cannot convert 'A<short int>' to 'int' in initialization
    4 | A<tttt> x = A<short>();
      |             ^~~~~~~~~~
      |             |
      |             A<short int>
Comment 2 Drea Pinski 2022-01-19 11:05:57 UTC
I can't find the bug right now but I think there is another bug which complains about how we use int for the type after an invalid template argument.
Comment 3 Drea Pinski 2022-01-19 11:18:33 UTC
from decl.cc:

      if (type_was_error_mark_node && template_parm_flag)
        /* FIXME we should be able to propagate the error_mark_node as is
           for other contexts too.  */
        type = error_mark_node;
      else
        type = integer_type_node;
Comment 4 Drea Pinski 2022-01-19 11:21:10 UTC
Doing this for GCC 12 is way too late; it is stage 4. I am going to try to handle this for GCC 13 though; there might be a few more places in the front-end that needs to handle error_mark_node but those should be done.
Also I noticed function return types might be an issue too (pt.cc has code which sets to integer_type_node for that case).
Comment 5 qingzhe huang 2022-01-21 14:48:43 UTC
Created attachment 52257 [details]
cp_parser_simulate_error  logic

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index b262b765a9a..988631a4248 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -24206,8 +24206,9 @@ cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags,
          /* OK */;
        else
          {
-           if (!cp_parser_simulate_error (parser))
-             {
+               if (parser->context && parser->context->status == CP_PARSER_STATUS_KIND_ERROR
+                               && cp_parser_simulate_error (parser))
+                       return error_mark_node;
                location_t loc = type_specifier_seq.locations[ds_type_spec];
                if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
                  {
@@ -24221,8 +24222,6 @@ cp_parser_type_id_1 (cp_parser *parser, cp_parser_flags flags,
                            auto_node);
                else
                  error_at (loc, "invalid use of %qT", auto_node);
-             }
-           return error_mark_node;
          }
       }
Comment 6 qingzhe huang 2022-01-21 15:02:41 UTC
How about this simple fix? (see the patch above.) 
Instead of return "error_mark_node" by condition of "!cp_parser_simulate_error", we now report error immediately. The rational of this fix is that "cp_parser_simulate_error" is only making sense when we already see error, i.e. "CP_PARSER_STATUS_KIND_ERROR". Otherwise, we should just report error.
I did a full build and check, it seems fine with me. For example, 

104091.cpp: In function ‘void g()’:
104091.cpp:8:7: error: ‘auto’ not permitted in template argument
    8 |     A<auto> x = A<short>();
      |       ^~~~
104091.cpp:8:13: error: variable ‘A<auto> x’ has initializer but incomplete type
    8 |     A<auto> x = A<short>();
      |             ^


Also I noticed previous testcase (i.e. g++.dg/DRs/dr625.C) is too relaxed with error message by allowing inaccurate "invalid template argument" or "cannot convert ..." instead of "auto not permitted".

If this makes sense to you, I am happy to provide more testcases and correct those old testcases.
Comment 7 Marek Polacek 2022-01-21 15:44:18 UTC
That looks wrong, if you want to give an error even when parsing tentatively, then you should use error_at.
Comment 8 Drea Pinski 2023-08-01 01:26:40 UTC
(In reply to Andrew Pinski from comment #3)
> from decl.cc:
> 
>       if (type_was_error_mark_node && template_parm_flag)
>         /* FIXME we should be able to propagate the error_mark_node as is
>            for other contexts too.  */
>         type = error_mark_node;
>       else
>         type = integer_type_node;

Changing this to not check template_parm_flag causes a regression in g++.dg/other/nontype-1.C . What happens is the type that happens here is now error_mark_node but the parser is not exacting that still. We get instead:
```
t1.cc:3:37: error: expected ‘)’ before ‘,’ token
    3 |            Op::first_argument_type a, // { dg-error "not a type" }
      |                                     ^
      |                                     )
t1.cc:2:11: note: to match this ‘(’
    2 | bool asfun(Op f,
      |           ^
```
Which is totally bad error recovery ...
Comment 9 Drea Pinski 2023-08-01 01:29:51 UTC
Not going to handle this as there will be many pathes inside the C++ front-end that will need to be changed to handle error_mark_node rather than just a type ...
Comment 10 Drea Pinski 2024-03-06 02:13:42 UTC
*** Bug 114248 has been marked as a duplicate of this bug. ***