Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 32 additions & 15 deletions src/Changes
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,21 @@ end now preserves the __weak__ attribute and suppresses the __always_inline__
attribute instead.


10/5/26 [GH #195]
C++-generating back end: dependent multi-dimensional subscripts

Copy link
Copy Markdown
Contributor

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.

10/6/26 [GH #27]
Clearer diagnostic when auto is deduced from an incomplete type

In cases in which template definitions are generated from the prototype
instantiation IL, when a dependent multi-dimensional subscript operation
appears in a template definition, the C++-generating back end previously
emitted only the first subscript. This is now fixed. For example, with
--c++23:
Deducing a plain "auto" (including cv-qualified "auto") from void or another
incomplete type used to be reported as a deduction failure. The type is now
deduced, and the usual incomplete-type diagnostic is issued, as it already
is for decltype(auto). For example:

template<typename T> auto f(const T &t) {
return t[1, 2]; // Previously generated as "t[1]"
}
void g();
auto x = g(); // Error: incomplete type "void" is not allowed
auto *p = g(); // Error: cannot deduce "auto" type

Forms that are not a plain "auto", such as "auto *", still fail deduction.

10/5/26 [GH #191]
C++-generating back end: inaccessible or out-of-scope template arguments

In certain complex cases, the C++-generating back end could put out a
template argument that uses an inaccessible or out-of-scope name, making
the generated code uncompilable. This is now fixed.
10/6/26 [GH #203]
Assertion failure on an empty diag_suppress pragma

Expand All @@ -92,6 +87,28 @@ That is now fixed: The missing argument is still diagnosed, and the code after
the pragma is parsed.


10/5/26 [GH #195]
C++-generating back end: dependent multi-dimensional subscripts

In cases in which template definitions are generated from the prototype
instantiation IL, when a dependent multi-dimensional subscript operation
appears in a template definition, the C++-generating back end previously
emitted only the first subscript. This is now fixed. For example, with
--c++23:

template<typename T> auto f(const T &t) {
return t[1, 2]; // Previously generated as "t[1]"
}


10/5/26 [GH #191]
C++-generating back end: inaccessible or out-of-scope template arguments

In certain complex cases, the C++-generating back end could put out a
template argument that uses an inaccessible or out-of-scope name, making
the generated code uncompilable. This is now fixed.


10/5/26 [GH #213]
White space lost in the pragma text for a "#pragma clang" directive

Expand Down
34 changes: 26 additions & 8 deletions src/overload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -4775,7 +4783,8 @@ deduction succeeds, FALSE if it fails.
if (!adjust_deduction_pair(&param_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
Expand Down Expand Up @@ -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)) &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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 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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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 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 no auto and int x = "s"; isn't diagnosed there either.

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,
Expand Down
30 changes: 30 additions & 0 deletions tests/tests/changes/.GH27.rto/default.1.1.txt
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".
14 changes: 14 additions & 0 deletions tests/tests/changes/.GH27_a.rto/default.1.1.txt
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".
6 changes: 6 additions & 0 deletions tests/tests/changes/.GH27_a.rto/default.2.1.txt
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".
6 changes: 6 additions & 0 deletions tests/tests/changes/.GH27_a.rto/default.3.1.txt
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".
6 changes: 6 additions & 0 deletions tests/tests/changes/.GH27_a.rto/default.4.1.txt
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".
14 changes: 14 additions & 0 deletions tests/tests/changes/.GH27_a.rto/edg_x86_64_cp.3.1.txt
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".
36 changes: 36 additions & 0 deletions tests/tests/changes/GH27.sft.cpp
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();
}

37 changes: 37 additions & 0 deletions tests/tests/changes/GH27_a.sft.cpp
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
Expand Up @@ -12,8 +12,8 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
^
detected during instantiation of "auto d<k>() [with k=0]" at line 41

"Test_name.c", line 46: error: cannot deduce "auto" type
"Test_name.c", line 46: error: incomplete type "void" is not allowed
auto e = []{ if constexpr (false) return 0; }(); // expected-error {{variable has incomplete type 'void'}}
^
^

2 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
auto bad_init_3 = [&a(void_fn())] {}; // expected-error {{cannot form a reference to 'void'}}
^

"Test_name.c", line 51: error: cannot deduce "auto" type
"Test_name.c", line 51: error: incomplete type "void" is not allowed
auto bad_init_4 = [a(void_fn())] {}; // expected-error {{has incomplete type 'void'}}
^

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
for (auto u : NoEnd()) { // expected-error {{no viable 'end' function available}}
^

"Test_name.c", line 180: error: cannot deduce "auto" type
for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void}}\
^

"Test_name.c", line 180: error: incomplete type "void" is not allowed
for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void}}\
^
Expand Down Expand Up @@ -305,4 +301,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
^
detected during instantiation of "void rdar13712739::foo(const T &) [with T=int]" at line 290

55 errors detected in the compilation of "Test_name.c".
54 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,6 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
for (auto u : NoEnd()) { // expected-error {{no viable 'end' function available}}
^

"Test_name.c", line 180: error: cannot deduce "auto" type
for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void}}\
^

"Test_name.c", line 180: error: incomplete type "void" is not allowed
for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void}}\
^
Expand Down Expand Up @@ -305,4 +301,4 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
^
detected during instantiation of "void rdar13712739::foo(const T &) [with T=int]" at line 290

55 errors detected in the compilation of "Test_name.c".
54 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,6 @@ fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
for (auto u : NoEnd()) { // expected-error {{no viable 'end' function available}}
^

"Test_name.c", line 180: error: cannot deduce "auto" type
for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void}}\
^

"Test_name.c", line 180: error: incomplete type "void" is not allowed
for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void}}\
^
Expand Down Expand Up @@ -309,4 +305,4 @@ fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
^
detected during instantiation of "void rdar13712739::foo(const T &) [with T=int]" at line 290

56 errors detected in the compilation of "Test_name.c".
55 errors detected in the compilation of "Test_name.c".
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".
Loading
Loading