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"
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>
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.
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;
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).
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; } }
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.
That looks wrong, if you want to give an error even when parsing tentatively, then you should use error_at.
(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 ...
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 ...
*** Bug 114248 has been marked as a duplicate of this bug. ***