Repository navigation
diagnose auto deduction from void more specifically, fix for [GH #27] #206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
748bb42
61356ec
ed026f4
bcef7db
90a5e26
aef05b9
3056726
a629bee
d6f5618
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65,7 +65,8 @@ static a_boolean adjust_deduction_pair( | |
| a_template_arg_ptr template_arg_list, | ||
| a_type_ptr *qc_param_type, | ||
| a_type_ptr *qc_arg_type, | ||
| a_boolean *consider_nondeduced); | ||
| a_boolean *consider_nondeduced, | ||
| a_boolean allow_incomplete_arg); | ||
| static a_boolean check_narrowing_conversion(an_operand *source_operand, | ||
| a_type_ptr dest_type, | ||
| a_boolean check_enum_target, | ||
|
|
@@ -1485,7 +1486,8 @@ from previous arguments; in the standard case, it is always NULL. | |
| (an_operand *)NULL, templ_params, | ||
| (a_template_arg *)NULL, | ||
| (a_type_ptr*)NULL, (a_type_ptr*)NULL, | ||
| (a_boolean *)NULL) && | ||
| (a_boolean *)NULL, | ||
| /*allow_incomplete_arg=*/FALSE) && | ||
| tentatively_matches_template_type(local_arg_type, | ||
| local_param_type, | ||
| templ_params, | ||
|
|
@@ -4272,7 +4274,8 @@ static a_boolean adjust_deduction_pair( | |
| a_template_arg_ptr template_arg_list, | ||
| a_type_ptr *qc_param_type, | ||
| a_type_ptr *qc_arg_type, | ||
| a_boolean *consider_nondeduced) | ||
| a_boolean *consider_nondeduced, | ||
| a_boolean allow_incomplete_arg) | ||
| /* | ||
| Adjust the types *p_param_type (a parameter type of a function template or a | ||
| type involving the "auto" type specifier) and *p_arg_type (the type of the | ||
|
|
@@ -4295,7 +4298,10 @@ are not removed. If consider_nondeduced is non-NULL and the reason for | |
| failure is that an indefinite function matches several ways, return | ||
| *consider_nondeduced TRUE. template_arg_list is used in some nonstandard | ||
| modes to introduce knowledge from previous arguments; in the standard case, | ||
| it is always NULL. | ||
| it is always NULL. allow_incomplete_arg allows an incomplete argument | ||
| type (including void) to be used for deduction. It is used for placeholder | ||
| type deduction, where an incomplete type error is diagnosed by the caller | ||
| instead of a deduction failure. | ||
| */ | ||
| { | ||
| a_boolean adjustment_okay = FALSE, indefinite_function_designator = FALSE; | ||
|
|
@@ -4399,7 +4405,8 @@ it is always NULL. | |
| void m() { f(*p); } | ||
| */ | ||
| complete_type_is_needed(arg_type); | ||
| if (is_incomplete_type(arg_type) && !is_managed_nullptr_type(arg_type)) { | ||
| if (is_incomplete_type(arg_type) && !is_managed_nullptr_type(arg_type) && | ||
| !allow_incomplete_arg) { | ||
| /* Although the managed (C++/CLI) nullptr type is incomplete and | ||
| cannot be used as the type of an object, for example, the Microsoft | ||
| compiler allows it as a template argument. */ | ||
|
|
@@ -4621,7 +4628,8 @@ deduction was successful: some cases are treated as "nondeduced contexts"). | |
| elem_operand, | ||
| templ_params, *template_arg_list, | ||
| &qc_param_type, &qc_arg_type, | ||
| &consider_nondeduced)) { | ||
| &consider_nondeduced, | ||
| /*allow_incomplete_arg=*/FALSE)) { | ||
| if (consider_nondeduced) continue; | ||
| deduction_okay = FALSE; | ||
| break; | ||
|
|
@@ -4775,7 +4783,8 @@ deduction succeeds, FALSE if it fails. | |
| if (!adjust_deduction_pair(¶m_type, &arg_type, operand, | ||
| templ_params, *template_arg_list, | ||
| &qc_param_type, &qc_arg_type, | ||
| &consider_nondeduced)) { | ||
| &consider_nondeduced, | ||
| /*allow_incomplete_arg=*/FALSE)) { | ||
| if (consider_nondeduced) { | ||
| /* The argument is an indefinite function that can match in more than | ||
| one way. Keep going without adding anything to the template | ||
|
|
@@ -31235,10 +31244,19 @@ TRUE and FALSE is returned. | |
| /* Adjust the argument and parameter types for deduction. Some types can | ||
| never succeed: Issue an error and don't attempt deduction any | ||
| further. */ | ||
| /* GCC and Microsoft don't diagnose incomplete-type errors in template | ||
| definitions, but for now the only way for us to emulate that is by | ||
| failing deduction in these cases (which we then allow, see | ||
| prescan_initializer_for_auto_type_deduction). */ | ||
| a_boolean allow_incomplete_arg = | ||
| !((gpp_version_is(any_version) || ms_version_is(any_version)) && | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The need for this change isn't entirely obvious. Was there any test case that would show undesirable results without this change? If so, it might be worth adding one example to your GH27.sft.cpp test to demonstrate the need for this change. Thanks for your continued work on this issue.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes. Without that check, a template definition is diagnosed even when the type is completed before instantiation: struct Later;
extern Later later_obj;
template<int> void use_later() { auto x = later_obj; }
struct Later { int n; };
void call_later() { use_later<0>(); }A deduction failure in the template definition is already suppressed in GNU and Microsoft modes. Diagnosing an incomplete type there instead turned decomp44 and decomp45 into errors. The check keeps that suppression. GH27 now has a --gnu_version run with this template, and it produces no diagnostic for use_later. The errors outside the template are unchanged.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the explanation. Unfortunately, it's a bit more complicated. So GCC and MSVC don't diagnose substitution failures and incomplete-type errors in template definition. We are only emulating the substitution failure part, but because we treated an incomplete type deduction as a substitution failure we kind of emulated that part as well. Your change would mean that for I think for now we'll have to duplicate the condition here: /* GCC and Microsoft don't diagnose incomplete-type errors in template
definitions, but for now the only way for us to emulate that is by
failing deduction in these cases (which we then allow, see
prescan_initializer_for_auto_type_deduction). */
a_boolean allow_incomplete_arg =
!((gpp_version_is(any_version) || ms_version_is(any_version)) &&
scope_stack_top().in_prototype_instantiation &&
innermost_function_scope != NULL);and run the template definition test not just in GCC mode, but all possible modes, i.e.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, that makes sense. I had folded the incomplete-type case into the GNU/Microsoft suppression, so standard and Clang modes went back to the deduction failure error for I've used your condition and comment as is, so incomplete-type deduction is only failed in a template definition in GNU and Microsoft modes, where The template definition test is now a separate test,
|
||
| scope_stack_top().in_prototype_instantiation && | ||
| innermost_function_scope != NULL); | ||
| if (!adjust_deduction_pair(&type, &arg_type, initializer_operand, | ||
| templ_param, (a_template_arg *)NULL, | ||
| &qc_param_type, &qc_arg_type, | ||
| (a_boolean *)NULL)) { | ||
| (a_boolean *)NULL, | ||
| allow_incomplete_arg)) { | ||
| okay = FALSE; | ||
| } else if (!deduce_from_one_pair(type, arg_type, | ||
| qc_param_type, qc_arg_type, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| fe_only -DTEST_NUMBER=1 --c++23 Test_name.c | ||
| "Test_name.c", line 27: error: incomplete type "void" is not allowed | ||
| auto v1 = void(); | ||
| ^ | ||
|
|
||
| "Test_name.c", line 28: error: incomplete type "void" is not allowed | ||
| decltype(auto) v2 = void(); | ||
| ^ | ||
|
|
||
| "Test_name.c", line 29: error: incomplete type "Incomplete" is not allowed | ||
| auto v3 = getIncomplete(); | ||
| ^ | ||
|
|
||
| "Test_name.c", line 30: error: incomplete type "void" is not allowed | ||
| auto opts = Args{}.parse(); | ||
| ^ | ||
|
|
||
| "Test_name.c", line 32: error: cannot deduce "auto" type | ||
| auto *v4 = void(); | ||
| ^ | ||
|
|
||
| "Test_name.c", line 33: error: cannot deduce "auto" type | ||
| auto *v5 = 1; | ||
| ^ | ||
|
|
||
| "Test_name.c", line 34: error: cannot deduce "auto" type | ||
| auto *p = g(); | ||
| ^ | ||
|
|
||
| 7 errors detected in the compilation of "Test_name.c". |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| fe_only -DTEST_NUMBER=1 --c++11 -A Test_name.c | ||
| "Test_name.c", line 14: error: incomplete type "void" is not allowed | ||
| auto v = void(); | ||
| ^ | ||
|
|
||
| "Test_name.c", line 20: error: incomplete type "void" is not allowed | ||
| auto v = void(); | ||
| ^ | ||
|
|
||
| "Test_name.c", line 29: error: incomplete type "Later" is not allowed | ||
| auto x = later_obj; | ||
| ^ | ||
|
|
||
| 3 errors detected in the compilation of "Test_name.c". |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| fe_only -DTEST_NUMBER=2 --c++11 --gnu_version 160200 Test_name.c | ||
| "Test_name.c", line 14: error: incomplete type "void" is not allowed | ||
| auto v = void(); | ||
| ^ | ||
|
|
||
| 1 error detected in the compilation of "Test_name.c". |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| fe_only -DTEST_NUMBER=3 --c++11 --clang_version 230100 Test_name.c | ||
| "Test_name.c", line 14: error: incomplete type "void" is not allowed | ||
| auto v = void(); | ||
| ^ | ||
|
|
||
| 1 error detected in the compilation of "Test_name.c". |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| fe_only -DTEST_NUMBER=4 --ms_c++20 --microsoft_version 1951 Test_name.c | ||
| "Test_name.c", line 14: error: incomplete type "void" is not allowed | ||
| auto v = void(); | ||
| ^ | ||
|
|
||
| 1 error detected in the compilation of "Test_name.c". |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| fe_only -DTEST_NUMBER=3 --c++11 --clang_version 230100 Test_name.c | ||
| "Test_name.c", line 14: error: incomplete type "void" is not allowed | ||
| auto v = void(); | ||
| ^ | ||
|
|
||
| "Test_name.c", line 20: error: incomplete type "void" is not allowed | ||
| auto v = void(); | ||
| ^ | ||
|
|
||
| "Test_name.c", line 29: error: incomplete type "Later" is not allowed | ||
| auto x = later_obj; | ||
| ^ | ||
|
|
||
| 3 errors detected in the compilation of "Test_name.c". |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| //type:fn | ||
| //options:--c++23 | ||
| //remark:[GH #27] Clearer diagnostic when auto deduces to void | ||
| // 10/6/26 [GH #27] | ||
| // | ||
| // A plain auto deduced from void or another incomplete type gets the | ||
| // incomplete-type diagnostic, matching decltype(auto). auto * still | ||
| // fails deduction. | ||
|
|
||
| struct Incomplete; | ||
|
|
||
| struct Incomplete &getIncomplete(); | ||
|
|
||
| struct Clap { | ||
| template <typename Spec> | ||
| auto parse(this Spec const& spec) { | ||
| } | ||
| }; | ||
|
|
||
| struct Args : Clap { | ||
| }; | ||
|
|
||
| void g(); | ||
|
|
||
| void f() | ||
| { | ||
| auto v1 = void(); | ||
| decltype(auto) v2 = void(); | ||
| auto v3 = getIncomplete(); | ||
| auto opts = Args{}.parse(); | ||
|
|
||
| auto *v4 = void(); | ||
| auto *v5 = 1; | ||
| auto *p = g(); | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| //type:fn | ||
| //options:--c++11 -A:--c++11 --gnu_version 160200:--c++11 --clang_version 230100:--ms_c++20 --microsoft_version 1951 | ||
| //remark:[GH #27] Incomplete auto deduction in a template definition | ||
| // 10/6/26 [GH #27] | ||
| // | ||
| // In standard and Clang modes, a plain auto deduced from an incomplete | ||
| // type in a template definition gets the incomplete-type diagnostic. GCC | ||
| // and Microsoft don't diagnose that in a template definition, so in GNU and | ||
| // Microsoft modes the definition is still accepted. Outside a template, | ||
| // the incomplete-type diagnostic is issued in every mode. | ||
|
|
||
| void not_a_template() | ||
| { | ||
| auto v = void(); | ||
| } | ||
|
|
||
| template<int> | ||
| void use_void() | ||
| { | ||
| auto v = void(); | ||
| } | ||
|
|
||
| struct Later; | ||
| extern Later later_obj; | ||
|
|
||
| template<int> | ||
| void use_later() | ||
| { | ||
| auto x = later_obj; | ||
| } | ||
|
|
||
| struct Later { int n; }; | ||
|
|
||
| void call_later() | ||
| { | ||
| use_later<0>(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --c++20 -DTEST3 Test_name.c | ||
| "Test_name.c", line 46: error: cannot deduce "auto" type | ||
| "Test_name.c", line 46: error: incomplete type "std::partial_ordering" is not allowed | ||
| auto res = a <=> b; | ||
| ^ | ||
| ^ | ||
|
|
||
| 1 error detected in the compilation of "Test_name.c". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am somehow seeing unrelated changes here (and the new Changes entry should be added to the top with the new date). Is this just something specific to this particular PR, or is there a deeper issue with the shared Changes file when iterating on a PR? @wchilders-nvidia any thoughts here?
Otherwise, I think it's good to go now.