Repository navigation
diagnose auto deduction from void more specifically, fix for [GH #27] - #206
Conversation
|
@wchilders-nvidia @daveedvdv could you please review this PR too? |
|
I'd prefer Maybe some (related) cases to think about (with the kind of error I'd expect here): struct Incomplete &getIncomplete();
void f()
{
auto v1 = void(); // error: incomplete type
decltype(auto) v2 = void(); // error: incomplete type
auto v3 = getIncomplete(); // error: incomplete type
auto *v4 = void(); // error: cannot deduce
auto *v5 = 1; // error: cannot deduce
}I wouldn't actually mind putting more information about the types for deduction failures in the diagnostics (for both |
indeed true, yeah, calling that a deduction failure was the wrong diagnosis. For
The CI mismatches were from the old wording. Recordings that now say incomplete type are updated, and the |
674c07f to
ea9361c
Compare
|
@wchilders-nvidia @daveedvdv @nv-cmeerw updated the PR as due to conflict of last changes, please check once more in you free time |
|
Hi @mohitmishra786, Thanks for working on this improvement! Can you add changes for the output differences in existing tests. See e.g. https://github.com/edgcpp/compiler/actions/runs/37155984995/job/111792273841 |
ea9361c to
ae2716c
Compare
That job is the earlier run, from before the recording updates. The tests whose output changed from "cannot deduce "auto" type" to the incomplete-type diagnostic now have updated default recordings: dcl.spec.auto/p2-1z, expr.prim.lambda/p11-1y, stmt.ranged/p1, auto-subst-failure, lambda-unevaluated, matrix-type-builtins-disabled, typeid-requires-typeinfo, and the new GH27 test. I rebased onto main again so the Changes file includes the 7.1 notes. Maybe we can trigger fresh run of CI and see everything again. |
| is also allowed through: the type is deduced, and the incomplete-type | ||
| diagnostic is issued for the variable (the same diagnostic as for | ||
| decltype(auto)). "auto *" and similar forms still fail deduction. */ | ||
| if (!(allow_incomplete_arg && is_template_param_type(param_type))) { |
There was a problem hiding this comment.
This if should just be folded into the enclosing if. The comment mentions "auto", but the condition tests for template parameter type (should probably use is_auto_type then). But I think this should just test for allow_incomplete_arg (and not test for "auto" at all here), as we only set allow_incomplete_arg for the placeholder type deduction case.
I am actually wondering if that whole is_incomplete_type check should go away completely. There is a deeper issue here, consider:
struct Incomplete &getIncomplete();
template<typename T>
void g(T, int) // 1
{ }
template<typename T>
void g(T &, long) // 2
{ }
void f()
{
g(getIncomplete(), 0);
}
Currently, we accept this, because we fail deduction for 1 and just call 2 instead. But we should succeed deduction for 1 and then diagnose the incomplete type error there.
We don't need to fix that with this change, but would be a good follow-up issue then.
There was a problem hiding this comment.
This
ifshould just be folded into the enclosing if. The comment mentions "auto", but the condition tests for template parameter type (should probably useis_auto_typethen). But I think this should just test forallow_incomplete_arg(and not test for "auto" at all here), as we only setallow_incomplete_argfor the placeholder type deduction case.I am actually wondering if that whole
is_incomplete_typecheck should go away completely. There is a deeper issue here, consider:struct Incomplete &getIncomplete(); template<typename T> void g(T, int) // 1 { } template<typename T> void g(T &, long) // 2 { } void f() { g(getIncomplete(), 0); }Currently, we accept this, because we fail deduction for 1 and just call 2 instead. But we should succeed deduction for 1 and then diagnose the incomplete type error there.
We don't need to fix that with this change, but would be a good follow-up issue then.
Updated the comment to talk about placeholder type deduction, and folded the check so it only looks at allow_incomplete_arg. The Changes entry no longer quotes the old diagnostic, and the examples use "// Error:".
I left the template case (g(getIncomplete(), 0) succeeding deduction and then diagnosing the incomplete type) for a follow-up. changes/GH27 still matches.
|
@nv-cmeerw update the pr as per the comments, workflows are yet to run after one of the maintainers approval |
|
@nv-cmeerw I see ci good now, once back please review, thanks |
| /* In a prototype instantiation a deduction failure is often | ||
| suppressed. Keep that behavior for an incomplete initializer: | ||
| the incomplete-type diagnostic is issued at instantiation. */ | ||
| a_boolean allow_incomplete_arg = |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 auto var = void() inside a template definition we wouldn't get the "incomplete type" error in standard or Clang modes any more (but instead get the old deduction failure error).
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. --c++11 -A:--c++11 --gnu_version 160200:--c++11 --clang_version 230100:--ms_c++20 --microsoft_version 1951
There was a problem hiding this comment.
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 auto var = void() in a template definition.
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 prescan_initializer_for_auto_type_deduction then allows it.
The template definition test is now a separate test, changes/GH27_a, because GH27 needs --c++23 for the explicit object parameter. GH27_a runs with --c++11 -A:--c++11 --gnu_version 160200:--c++11 --clang_version 230100:--ms_c++20 --microsoft_version 1951. It also has a non-template auto v = void() so that every mode has an error, as the test type requires. Results:
- strict mode: "incomplete type" errors in the template definitions
- GNU and Microsoft modes: no diagnostic in the template definitions
- Clang mode: "incomplete type" errors in the template definitions with the C++-generating back end config (recorded as
edg_x86_64_cp.3.1.txt). In the default config, Clang mode reports nothing inside an uninstantiated template body. That isn't specific to this change: a template body with noautoandint x = "s";isn't diagnosed there either.
c572536 to
a629bee
Compare
|
@nv-cmeerw updated the PR with above comments and rebased to the latest changes |
| auto *p = g(); // Error: cannot deduce "auto" type | ||
|
|
||
| Forms that are not a plain "auto", such as "auto *", still fail deduction. | ||
| The diagnostic is not issued while scanning a template definition, because |
There was a problem hiding this comment.
I don't think we need to mention the template definition part here, as it's just keeping the existing behaviour.
There was a problem hiding this comment.
Agreed, removed.
…icrosoft modes. [GH edgcpp#27]
|
@nv-cmeerw updated the PR as per the comments and the reasoning, up for review |
|
|
||
|
|
||
| 10/5/26 [GH #195] | ||
| C++-generating back end: dependent multi-dimensional subscripts |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
That was specific to this PR. While resolving the src/Changes conflicts in earlier rebases, I moved the GH #195 and GH #191 entries below GH #203, so the diff showed them as removed and re-added. I've now taken src/Changes from main as is and only added the GH #27 entry at the top of 7.1 with today's date (10/9/26), so the diff is just that one entry.
The last CI run also failed edg_x86_32_cp on changes/GH27_a: in that config, Clang mode reports the template-definition errors just as edg_x86_64_cp does, so I've added the matching edg_x86_32_cp.3.1.txt recording.
…x86_32_cp. [GH edgcpp#27]
|
@nv-cmeerw now ci passes and everything aligned, let me know if anything more you see not aligning, I updated the order fix too |

Fixes #27
deducing auto from a void expression used to say only cannot deduce "auto" type, because void is incomplete and deduction stopped before it could name the type. Those cases now say cannot deduce "auto" type from type "void". That covers the reported example, auto x = g(), auto &&, const auto, auto *, new auto(...), and auto * return types. decltype(auto) is unchanged: deduction still succeeds, and the existing incomplete type "void" is not allowed diagnostic is issued.
one leftover generic message remains on auto *q = new auto(g()). The new auto part uses the new wording. The pointer variable then sees a failed new-expression, not a void expression, so it keeps the generic message.
testing is done like below
edg-docker-test --non-interactive --posture=quick-c-fe changes/GH27 on the linux-gcc-debug Docker build. The test is tests/tests/changes/GH27.sft.cpp (//type:fn, --c++23). The first run passed with no previous output. -W wrote tests/tests/changes/.GH27.rto/default.1.1.txt, and a second run matched that recording.