From 9ccb6bfa9fe79ad2e7d5f95b98bbce76dea306ec Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 15 May 2026 14:24:03 -0500 Subject: [PATCH 1/7] [WIP] Implement `auto` for C++11-style type deduction This is a partial proof of concept of C++11-stlye type deduction being added to HLSL under the 202x language mode. This is still missing special handling for non-deducable special HLSL types. The main one that comes to mind is the type of the `ResourceDescriptorHeap` and `SamplerDescriptorHeap`. --- .../clang/Basic/DiagnosticParseKinds.td | 3 +- tools/clang/include/clang/Lex/Token.h | 2 +- tools/clang/lib/Parse/ParseDecl.cpp | 3 +- tools/clang/lib/Sema/DeclSpec.cpp | 10 ++++- tools/clang/lib/Sema/SemaDecl.cpp | 1 - tools/clang/test/HLSL/cpp-errors-hv2015.hlsl | 5 ++- tools/clang/test/HLSL/cpp-errors.hlsl | 5 ++- .../hlsl/auto/auto-no-pointer.hlsl | 12 +++++ .../hlsl/auto/auto-no-reference.hlsl | 13 ++++++ .../hlsl/auto/auto-template.hlsl | 37 ++++++++++++++++ .../hlsl/auto/auto-variable-deduction.hlsl | 44 +++++++++++++++++++ 11 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-pointer.hlsl create mode 100644 tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl create mode 100644 tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-template.hlsl create mode 100644 tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.hlsl diff --git a/tools/clang/include/clang/Basic/DiagnosticParseKinds.td b/tools/clang/include/clang/Basic/DiagnosticParseKinds.td index e328393726..ac4bad2cc2 100644 --- a/tools/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -285,7 +285,8 @@ def warn_cxx98_compat_trailing_return_type : Warning< "trailing return types are incompatible with C++98">, InGroup, DefaultIgnore; def ext_auto_type_specifier : ExtWarn< - "'auto' type specifier is a C++11 extension">, InGroup; + "'auto' type specifier is a %select{C++11|HLSL 202x}0 extension">, + InGroup; def warn_auto_storage_class : Warning< "'auto' storage class specifier is redundant and incompatible with C++11">, InGroup, DefaultIgnore; diff --git a/tools/clang/include/clang/Lex/Token.h b/tools/clang/include/clang/Lex/Token.h index 7cb0118596..42e45bc035 100644 --- a/tools/clang/include/clang/Lex/Token.h +++ b/tools/clang/include/clang/Lex/Token.h @@ -295,7 +295,7 @@ class Token { // HLSL Change Starts bool isHLSLReserved() const { return is(tok::kw___is_signed) || is(tok::kw___declspec) || - is(tok::kw___forceinline) || is(tok::kw_auto) || is(tok::kw_catch) || + is(tok::kw___forceinline) || is(tok::kw_catch) || is(tok::kw_const_cast) || is(tok::kw_delete) || is(tok::kw_dynamic_cast) || is(tok::kw_enum) || is(tok::kw_explicit) || is(tok::kw_friend) || is(tok::kw_goto) || diff --git a/tools/clang/lib/Parse/ParseDecl.cpp b/tools/clang/lib/Parse/ParseDecl.cpp index c91c8940a4..d6e5c3b58e 100644 --- a/tools/clang/lib/Parse/ParseDecl.cpp +++ b/tools/clang/lib/Parse/ParseDecl.cpp @@ -3918,8 +3918,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; // HLSL Change Ends case tok::kw_auto: - if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - auto is reserved for HLSL - if (getLangOpts().CPlusPlus11) { + if (getLangOpts().CPlusPlus11 || getLangOpts().HLSL) { // HLSL Change if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, PrevSpec, DiagID, Policy); diff --git a/tools/clang/lib/Sema/DeclSpec.cpp b/tools/clang/lib/Sema/DeclSpec.cpp index 37c1554092..455f755242 100644 --- a/tools/clang/lib/Sema/DeclSpec.cpp +++ b/tools/clang/lib/Sema/DeclSpec.cpp @@ -1158,8 +1158,14 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP, const PrintingPoli } // Diagnose if we've recovered from an ill-formed 'auto' storage class // specifier in a pre-C++11 dialect of C++. - if (!PP.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto) - Diag(D, TSTLoc, diag::ext_auto_type_specifier); + // HLSL Change Begin - HLSL supports 'auto' as a type specifier in 202x+. + if (!(PP.getLangOpts().CPlusPlus11 || + (PP.getLangOpts().HLSL && + PP.getLangOpts().HLSLVersion >= hlsl::LangStd::v202x)) && + TypeSpecType == TST_auto) + Diag(D, TSTLoc, diag::ext_auto_type_specifier) + << /* HLSL */ PP.getLangOpts().HLSL; + // HLSL Change End if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus11 && StorageClassSpec == SCS_auto) Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class) diff --git a/tools/clang/lib/Sema/SemaDecl.cpp b/tools/clang/lib/Sema/SemaDecl.cpp index a772054960..b6fb971aac 100644 --- a/tools/clang/lib/Sema/SemaDecl.cpp +++ b/tools/clang/lib/Sema/SemaDecl.cpp @@ -9047,7 +9047,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // If this is a redeclaration, check that the type we just deduced matches // the previously declared type. - assert(!getLangOpts().HLSL && "auto types are not supported - merge type below is inconsequential"); // HLSL Change if (VarDecl *Old = VDecl->getPreviousDecl()) { // We never need to merge the type, because we cannot form an incomplete // array of auto, nor deduce such a type. diff --git a/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl b/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl index 57c512741c..99a92fac6e 100644 --- a/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl +++ b/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl @@ -12,7 +12,7 @@ s_arr_i_f arr_struct_two[] = { 1, 2, 3, 4 }; int g_int; typeof(g_int) g_typeof_int; // expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{expected ';' after top level declarator}} expected-error {{unknown type name 'typeof'; did you mean 'typedef'?}} typedef int (*fn_int)(int); // expected-error {{pointers are unsupported in HLSL}} -auto g_auto = 3; // expected-error {{'auto' is a reserved keyword in HLSL}} expected-error {{HLSL requires a type specifier for all declarations}} +auto g_auto = 3; // auto is now supported in HLSL via type deduction; no error expected __is_signed g_is_signed; // expected-error {{'__is_signed' is a reserved keyword in HLSL}} expected-error {{HLSL requires a type specifier for all declarations}} register int g_register; // expected-error {{'register' is a reserved keyword in HLSL}} __thread int g_thread; // expected-error {{'__thread' is a reserved keyword in HLSL}} @@ -68,7 +68,8 @@ void fn_throw() throw() { } // expected-error {{exception specification is unsup void fn_noexcept() noexcept { }; // expected-error {{expected function body after function declarator}} // This would be a failure because of unsupported trailer return types, but we mis-parse it differently. -auto fn_trailing() -> int { return 1; } ; // expected-error {{'auto' is a reserved keyword in HLSL}} expected-error {{expected function body after function declarator}} +// auto is now type-deduced so no reserved keyword error; only the trailing return type syntax causes an error. +auto fn_trailing() -> int { return 1; } ; // expected-error {{expected function body after function declarator}} void fn_param_with_default(int val = 1) { } void fn_with_variadic(int a, ...) { } // expected-error {{variadic arguments is unsupported in HLSL}} diff --git a/tools/clang/test/HLSL/cpp-errors.hlsl b/tools/clang/test/HLSL/cpp-errors.hlsl index bee34d249b..1ecf4a57e1 100644 --- a/tools/clang/test/HLSL/cpp-errors.hlsl +++ b/tools/clang/test/HLSL/cpp-errors.hlsl @@ -12,7 +12,7 @@ s_arr_i_f arr_struct_two[] = { 1, 2, 3, 4 }; int g_int; typeof(g_int) g_typeof_int; // expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{expected ';' after top level declarator}} expected-error {{unknown type name 'typeof'; did you mean 'typedef'?}} typedef int (*fn_int)(int); // expected-error {{pointers are unsupported in HLSL}} -auto g_auto = 3; // expected-error {{'auto' is a reserved keyword in HLSL}} expected-error {{HLSL requires a type specifier for all declarations}} +auto g_auto = 3; // auto is now supported in HLSL via type deduction; no error expected __is_signed g_is_signed; // expected-error {{'__is_signed' is a reserved keyword in HLSL}} expected-error {{HLSL requires a type specifier for all declarations}} register int g_register; // expected-error {{'register' is a reserved keyword in HLSL}} __thread int g_thread; // expected-error {{'__thread' is a reserved keyword in HLSL}} @@ -65,7 +65,8 @@ void fn_throw() throw() { } // expected-error {{exception specification is unsup void fn_noexcept() noexcept { }; // expected-error {{expected function body after function declarator}} // This would be a failure because of unsupported trailer return types, but we mis-parse it differently. -auto fn_trailing() -> int { return 1; } ; // expected-error {{'auto' is a reserved keyword in HLSL}} expected-error {{expected function body after function declarator}} +// auto is now type-deduced so no reserved keyword error; only the trailing return type syntax causes an error. +auto fn_trailing() -> int { return 1; } ; // expected-error {{expected function body after function declarator}} void fn_param_with_default(int val = 1) { } void fn_with_variadic(int a, ...) { } // expected-error {{variadic arguments is unsupported in HLSL}} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-pointer.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-pointer.hlsl new file mode 100644 index 0000000000..53a78278e2 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-pointer.hlsl @@ -0,0 +1,12 @@ +// RUN: not %dxc -T cs_6_0 %s 2>&1 | FileCheck %s + +// Test that 'auto' cannot be used to declare pointer types in HLSL. +// Pointers are unsupported in HLSL. + +// CHECK: error: pointers are unsupported in HLSL + +[numthreads(1,1,1)] +void main() { + int x = 1; + auto* ptr = &x; +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl new file mode 100644 index 0000000000..7f6e00bacb --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl @@ -0,0 +1,13 @@ +// RUN: not %dxc -T cs_6_0 -HV 202x %s 2>&1 | FileCheck %s + +// Test that 'auto' cannot be used to declare reference types in HLSL. +// References are unsupported in HLSL. + +// CHECK: error: references are unsupported in HLSL + +int gVal = 42; + +[numthreads(1,1,1)] +void main() { + auto& ref = gVal; +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-template.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-template.hlsl new file mode 100644 index 0000000000..e8f218d237 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-template.hlsl @@ -0,0 +1,37 @@ +// RUN: %dxc -T cs_6_0 -HV 202x -fcgl %s | FileCheck %s +// RUN: %dxc -T cs_6_0 -HV 202x %s | FileCheck %s --check-prefix=DXIL + +// Test that the 'auto' keyword works correctly in template contexts in HLSL: +// - auto variables inside template function bodies +// - auto variables assigned from results of template function instantiations + +// CHECK-LABEL: define void @main() +// DXIL: define void @main() + +RWBuffer output : register(u0); + +// Template with explicit return type; auto is used inside the body. +template +T square(T val) { + auto result = val * val; + return result; +} + +// Template with explicit return type using a conditional expression. +template +T clampPositive(T val) { + auto zero = (T)0; + auto clamped = val < zero ? zero : val; + return clamped; +} + +[numthreads(1,1,1)] +void main() { + // auto variables assigned from template instantiation results. + auto a = square(5); // instantiated as int + auto b = square(2.5f); // instantiated as float + auto c = clampPositive(-3); // instantiated as int, result = 0 + auto d = clampPositive(1.5f); // instantiated as float + + output[0] = (float)a + b + (float)c + d; +} diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.hlsl new file mode 100644 index 0000000000..05ee924f73 --- /dev/null +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.hlsl @@ -0,0 +1,44 @@ +// RUN: %dxc -T cs_6_0 -E main - %s | FileCheck %s +// RUN: %dxc -T cs_6_0 -E main -HV 202x -fcgl %s | FileCheck %s +// RUN: %dxc -T cs_6_0 -E main -HV 202x %s | FileCheck %s --check-prefix=DXIL + +// Test that the 'auto' keyword can be used to declare variables with inferred +// types from initialization expressions in HLSL. + +// CHECK-LABEL: define void @main() +// CHECK: %a = alloca i32 +// CHECK: %b = alloca float +// CHECK: %c = alloca i32 +// CHECK: %d = alloca <4 x float> +// CHECK: store i32 1, i32* %a +// CHECK: store float 2.000000e+00, float* %b +// CHECK: store i32 1, i32* %c + +// DXIL: define void @main() + +RWBuffer output : register(u0); + +[numthreads(1,1,1)] +void main() { + // Auto deduces int from integer literal + // expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} + auto a = 1; + // Auto deduces float from float literal + // expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} + auto b = 2.0f; + // Auto deduces bool (stored as i32) from bool literal + // expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} + auto c = true; + // Auto deduces float4 from vector type + // expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} + auto d = float4(1.0f, 2.0f, 3.0f, 4.0f); + + // Auto from arithmetic expressions + // expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} + auto sum = a + a; + // expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} + auto product = b * b; + + // Use the values to prevent dead-code elimination + output[0] = (float)sum + product + d.x + (float)c; +} From 5756d3a4f9f6f746ff02dee88e4ab1f6f17a429a Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Fri, 15 May 2026 15:59:48 -0500 Subject: [PATCH 2/7] Doh! Fix broken test. --- .../hlsl/auto/auto-variable-deduction.hlsl | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.hlsl index 05ee924f73..25522f0fde 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.hlsl @@ -1,20 +1,20 @@ -// RUN: %dxc -T cs_6_0 -E main - %s | FileCheck %s +// RUN: %dxc -T cs_6_0 -E main - %s -verify // RUN: %dxc -T cs_6_0 -E main -HV 202x -fcgl %s | FileCheck %s -// RUN: %dxc -T cs_6_0 -E main -HV 202x %s | FileCheck %s --check-prefix=DXIL +// RUN: %dxc -T cs_6_0 -E main -HV 202x %s | FileCheck %s --check-prefix=CHECK_DXIL // Test that the 'auto' keyword can be used to declare variables with inferred // types from initialization expressions in HLSL. // CHECK-LABEL: define void @main() -// CHECK: %a = alloca i32 -// CHECK: %b = alloca float -// CHECK: %c = alloca i32 -// CHECK: %d = alloca <4 x float> -// CHECK: store i32 1, i32* %a -// CHECK: store float 2.000000e+00, float* %b -// CHECK: store i32 1, i32* %c +// CHECK: [[A:%[a-zA-Z0-9_]+]] = alloca i32 +// CHECK: [[B:%[a-zA-Z0-9_]+]] = alloca float +// CHECK: [[C:%[a-zA-Z0-9_]+]] = alloca i32 +// CHECK: [[D:%[a-zA-Z0-9_]+]] = alloca <4 x float> +// CHECK: store i32 1, i32* [[A]] +// CHECK: store float 2.000000e+00, float* [[B]] +// CHECK: store i32 1, i32* [[C]] -// DXIL: define void @main() +// CHECK_DXIL: define void @main() RWBuffer output : register(u0); From c5c4908faec7c4091024388f8f5bbaa88ebb1852 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 18 May 2026 12:41:02 -0500 Subject: [PATCH 3/7] Fix tests ../tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-pointer.hlsl ../tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl --- .../test/HLSLFileCheckLit/hlsl/auto/auto-no-pointer.hlsl | 6 ++---- .../test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-pointer.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-pointer.hlsl index 53a78278e2..425a69cd8c 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-pointer.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-pointer.hlsl @@ -1,12 +1,10 @@ -// RUN: not %dxc -T cs_6_0 %s 2>&1 | FileCheck %s +// RUN: %dxc -T cs_6_0 -HV 202x -verify %s // Test that 'auto' cannot be used to declare pointer types in HLSL. // Pointers are unsupported in HLSL. -// CHECK: error: pointers are unsupported in HLSL - [numthreads(1,1,1)] void main() { int x = 1; - auto* ptr = &x; + auto* ptr = &x; // expected-error {{pointers are unsupported in HLSL}} } diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl index 7f6e00bacb..499c26aec7 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-no-reference.hlsl @@ -1,13 +1,11 @@ -// RUN: not %dxc -T cs_6_0 -HV 202x %s 2>&1 | FileCheck %s +// RUN: %dxc -T cs_6_0 -HV 202x -verify %s // Test that 'auto' cannot be used to declare reference types in HLSL. // References are unsupported in HLSL. -// CHECK: error: references are unsupported in HLSL - int gVal = 42; [numthreads(1,1,1)] void main() { - auto& ref = gVal; + auto& ref = gVal; // expected-error {{references are unsupported in HLSL}} } From 9c93f9a3525aaee7ad59eb988248d6378763211f Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 18 May 2026 12:49:46 -0500 Subject: [PATCH 4/7] disable auto in HLSL 2015 --- tools/clang/lib/Parse/ParseDecl.cpp | 5 +++++ tools/clang/test/HLSL/cpp-errors-hv2015.hlsl | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/clang/lib/Parse/ParseDecl.cpp b/tools/clang/lib/Parse/ParseDecl.cpp index d6e5c3b58e..85404a1673 100644 --- a/tools/clang/lib/Parse/ParseDecl.cpp +++ b/tools/clang/lib/Parse/ParseDecl.cpp @@ -3918,6 +3918,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; // HLSL Change Ends case tok::kw_auto: + // HLSL Change Begin - auto is reserved for HLSL 2015 and earlier. + if (getLangOpts().HLSL && + getLangOpts().HLSLVersion <= hlsl::LangStd::v2015) + goto HLSLReservedKeyword; + // HLSL Change End if (getLangOpts().CPlusPlus11 || getLangOpts().HLSL) { // HLSL Change if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, diff --git a/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl b/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl index 99a92fac6e..01175bfdc3 100644 --- a/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl +++ b/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl @@ -12,7 +12,7 @@ s_arr_i_f arr_struct_two[] = { 1, 2, 3, 4 }; int g_int; typeof(g_int) g_typeof_int; // expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{expected ';' after top level declarator}} expected-error {{unknown type name 'typeof'; did you mean 'typedef'?}} typedef int (*fn_int)(int); // expected-error {{pointers are unsupported in HLSL}} -auto g_auto = 3; // auto is now supported in HLSL via type deduction; no error expected +auto g_auto = 3; // expected-error {{'auto' is a reserved keyword in HLSL}} expected-error {{HLSL requires a type specifier for all declarations}} __is_signed g_is_signed; // expected-error {{'__is_signed' is a reserved keyword in HLSL}} expected-error {{HLSL requires a type specifier for all declarations}} register int g_register; // expected-error {{'register' is a reserved keyword in HLSL}} __thread int g_thread; // expected-error {{'__thread' is a reserved keyword in HLSL}} @@ -69,7 +69,7 @@ void fn_noexcept() noexcept { }; // expected-error {{expected function body afte // This would be a failure because of unsupported trailer return types, but we mis-parse it differently. // auto is now type-deduced so no reserved keyword error; only the trailing return type syntax causes an error. -auto fn_trailing() -> int { return 1; } ; // expected-error {{expected function body after function declarator}} +auto fn_trailing() -> int { return 1; } ; // expected-error {{'auto' is a reserved keyword in HLSL}} expected-error {{expected function body after function declarator}} void fn_param_with_default(int val = 1) { } void fn_with_variadic(int a, ...) { } // expected-error {{variadic arguments is unsupported in HLSL}} From 588cbcd022c92cbac1c7eb02b836f5e506962e29 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 18 May 2026 12:51:03 -0500 Subject: [PATCH 5/7] Remove stale comment --- tools/clang/test/HLSL/cpp-errors-hv2015.hlsl | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl b/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl index 01175bfdc3..57c512741c 100644 --- a/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl +++ b/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl @@ -68,7 +68,6 @@ void fn_throw() throw() { } // expected-error {{exception specification is unsup void fn_noexcept() noexcept { }; // expected-error {{expected function body after function declarator}} // This would be a failure because of unsupported trailer return types, but we mis-parse it differently. -// auto is now type-deduced so no reserved keyword error; only the trailing return type syntax causes an error. auto fn_trailing() -> int { return 1; } ; // expected-error {{'auto' is a reserved keyword in HLSL}} expected-error {{expected function body after function declarator}} void fn_param_with_default(int val = 1) { } From a75c33de49a168b92f9ab587987e707aac8f011c Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Tue, 19 May 2026 10:12:59 -0500 Subject: [PATCH 6/7] Improve test cases ../tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-template.hlsl ../tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.h lsl --- .../hlsl/auto/auto-template.hlsl | 10 +++++++--- .../hlsl/auto/auto-variable-deduction.hlsl | 17 ++++++++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-template.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-template.hlsl index e8f218d237..885d2226ae 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-template.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-template.hlsl @@ -1,12 +1,10 @@ // RUN: %dxc -T cs_6_0 -HV 202x -fcgl %s | FileCheck %s -// RUN: %dxc -T cs_6_0 -HV 202x %s | FileCheck %s --check-prefix=DXIL // Test that the 'auto' keyword works correctly in template contexts in HLSL: // - auto variables inside template function bodies // - auto variables assigned from results of template function instantiations -// CHECK-LABEL: define void @main() -// DXIL: define void @main() + RWBuffer output : register(u0); @@ -25,6 +23,12 @@ T clampPositive(T val) { return clamped; } +// CHECK-LABEL: define void @main() +// CHECK: {{.*}} = alloca i32 +// CHECK: {{.*}} = alloca float +// CHECK: {{.*}} = alloca i32 +// CHECK: {{.*}} = alloca float + [numthreads(1,1,1)] void main() { // auto variables assigned from template instantiation results. diff --git a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.hlsl b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.hlsl index 25522f0fde..8cc375a02e 100644 --- a/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.hlsl +++ b/tools/clang/test/HLSLFileCheckLit/hlsl/auto/auto-variable-deduction.hlsl @@ -1,6 +1,5 @@ // RUN: %dxc -T cs_6_0 -E main - %s -verify // RUN: %dxc -T cs_6_0 -E main -HV 202x -fcgl %s | FileCheck %s -// RUN: %dxc -T cs_6_0 -E main -HV 202x %s | FileCheck %s --check-prefix=CHECK_DXIL // Test that the 'auto' keyword can be used to declare variables with inferred // types from initialization expressions in HLSL. @@ -10,12 +9,15 @@ // CHECK: [[B:%[a-zA-Z0-9_]+]] = alloca float // CHECK: [[C:%[a-zA-Z0-9_]+]] = alloca i32 // CHECK: [[D:%[a-zA-Z0-9_]+]] = alloca <4 x float> +// CHECK: {{.*}} = alloca i32 +// CHECK: {{.*}} = alloca float +// CHECK: {{.*}} = alloca <4 x float> +// CHECK: {{.*}} = alloca i32 +// CHECK: {{.*}} = alloca float // CHECK: store i32 1, i32* [[A]] // CHECK: store float 2.000000e+00, float* [[B]] // CHECK: store i32 1, i32* [[C]] -// CHECK_DXIL: define void @main() - RWBuffer output : register(u0); [numthreads(1,1,1)] @@ -39,6 +41,15 @@ void main() { // expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} auto product = b * b; + // expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} + auto mulAdd = mad(d, d, d); + + // expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} + auto m = min(sum, c); + + // expected-warning@+1 {{'auto' type specifier is a HLSL 202x extension}} + auto dP = dot(d, d); + // Use the values to prevent dead-code elimination output[0] = (float)sum + product + d.x + (float)c; } From ef469a29a026f08635228d2a600c7a7081f42978 Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Wed, 20 May 2026 13:56:05 -0500 Subject: [PATCH 7/7] Add two tests covering spirv generation I realized none of the other tests covered SPIRV code generation, and while there were no necessary code changes it is nice to have the coverage for confidence. --- .../test/CodeGenSPIRV/var.auto.deduction.hlsl | 51 ++++++++++++++++++ .../test/CodeGenSPIRV/var.auto.template.hlsl | 53 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 tools/clang/test/CodeGenSPIRV/var.auto.deduction.hlsl create mode 100644 tools/clang/test/CodeGenSPIRV/var.auto.template.hlsl diff --git a/tools/clang/test/CodeGenSPIRV/var.auto.deduction.hlsl b/tools/clang/test/CodeGenSPIRV/var.auto.deduction.hlsl new file mode 100644 index 0000000000..553bb6642a --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/var.auto.deduction.hlsl @@ -0,0 +1,51 @@ +// RUN: %dxc -T cs_6_0 -E main -HV 202x -fcgl %s -spirv | FileCheck %s + +// Test that the 'auto' keyword can be used to declare variables with inferred +// types from initialization expressions when targeting SPIR-V. + +// CHECK: [[INT:%[a-zA-Z0-9_]+]] = OpTypeInt 32 1 +// CHECK: [[INT_1:%[a-zA-Z0-9_]+]] = OpConstant [[INT]] 1 +// CHECK: [[FLOAT:%[a-zA-Z0-9_]+]] = OpTypeFloat 32 +// CHECK: [[FLOAT_2:%[a-zA-Z0-9_]+]] = OpConstant [[FLOAT]] 2 +// CHECK: [[BOOL:%[a-zA-Z0-9_]+]] = OpTypeBool +// CHECK: [[TRUE:%[a-zA-Z0-9_]+]] = OpConstantTrue [[BOOL]] +// CHECK: [[V4FLOAT:%[a-zA-Z0-9_]+]] = OpTypeVector [[FLOAT]] 4 +// CHECK: [[VEC_CONST:%[a-zA-Z0-9_]+]] = OpConstantComposite [[V4FLOAT]] {{%[a-zA-Z0-9_]+}} [[FLOAT_2]] {{%[a-zA-Z0-9_]+}} {{%[a-zA-Z0-9_]+}} + +// CHECK: [[PTR_INT:%_ptr_Function_int]] = OpTypePointer Function [[INT]] +// CHECK: [[PTR_FLOAT:%_ptr_Function_float]] = OpTypePointer Function [[FLOAT]] +// CHECK: [[PTR_BOOL:%_ptr_Function_bool]] = OpTypePointer Function [[BOOL]] +// CHECK: [[PTR_V4FLOAT:%_ptr_Function_v4float]] = OpTypePointer Function [[V4FLOAT]] + +// CHECK: %a = OpVariable [[PTR_INT]] Function +// CHECK: %b = OpVariable [[PTR_FLOAT]] Function +// CHECK: %c = OpVariable [[PTR_BOOL]] Function +// CHECK: %d = OpVariable [[PTR_V4FLOAT]] Function +// CHECK: %sum = OpVariable [[PTR_INT]] Function +// CHECK: %product = OpVariable [[PTR_FLOAT]] Function + +// CHECK: OpStore %a [[INT_1]] +// CHECK: OpStore %b [[FLOAT_2]] +// CHECK: OpStore %c [[TRUE]] +// CHECK: OpStore %d [[VEC_CONST]] + +RWBuffer output : register(u0); + +[numthreads(1,1,1)] +void main() { + // Auto deduces int from integer literal + auto a = 1; + // Auto deduces float from float literal + auto b = 2.0f; + // Auto deduces bool from bool literal + auto c = true; + // Auto deduces float4 from vector type + auto d = float4(1.0f, 2.0f, 3.0f, 4.0f); + + // Auto from arithmetic expressions + auto sum = a + a; + auto product = b * b; + + // Use the values to prevent dead-code elimination + output[0] = (float)sum + product + d.x + (float)c; +} diff --git a/tools/clang/test/CodeGenSPIRV/var.auto.template.hlsl b/tools/clang/test/CodeGenSPIRV/var.auto.template.hlsl new file mode 100644 index 0000000000..7a2b5acf4d --- /dev/null +++ b/tools/clang/test/CodeGenSPIRV/var.auto.template.hlsl @@ -0,0 +1,53 @@ +// RUN: %dxc -T cs_6_0 -E main -HV 202x -fcgl %s -spirv | FileCheck %s + +// Test that the 'auto' keyword works correctly in template contexts when +// targeting SPIR-V: +// - auto variables inside template function bodies +// - auto variables assigned from results of template function instantiations + +RWBuffer output : register(u0); + +// Template with explicit return type; auto is used inside the body. +template +T square(T val) { + auto result = val * val; + return result; +} + +// Template with explicit return type using a conditional expression. +template +T clampPositive(T val) { + auto zero = (T)0; + auto clamped = val < zero ? zero : val; + return clamped; +} + +// CHECK: [[INT:%[a-zA-Z0-9_]+]] = OpTypeInt 32 1 +// CHECK: [[FLOAT:%[a-zA-Z0-9_]+]] = OpTypeFloat 32 +// CHECK: [[PTR_INT:%_ptr_Function_int]] = OpTypePointer Function [[INT]] +// CHECK: [[PTR_FLOAT:%_ptr_Function_float]] = OpTypePointer Function [[FLOAT]] + +// Auto-deduced locals in main() instantiated for int and float. +// CHECK: %a = OpVariable [[PTR_INT]] Function +// CHECK: %b = OpVariable [[PTR_FLOAT]] Function +// CHECK: %c = OpVariable [[PTR_INT]] Function +// CHECK: %d = OpVariable [[PTR_FLOAT]] Function + +// Auto inside template bodies retains correct types after instantiation. +// CHECK: %result = OpVariable [[PTR_INT]] Function +// CHECK: %result_0 = OpVariable [[PTR_FLOAT]] Function +// CHECK: %zero = OpVariable [[PTR_INT]] Function +// CHECK: %clamped = OpVariable [[PTR_INT]] Function +// CHECK: %zero_0 = OpVariable [[PTR_FLOAT]] Function +// CHECK: %clamped_0 = OpVariable [[PTR_FLOAT]] Function + +[numthreads(1,1,1)] +void main() { + // auto variables assigned from template instantiation results. + auto a = square(5); // instantiated as int + auto b = square(2.5f); // instantiated as float + auto c = clampPositive(-3); // instantiated as int + auto d = clampPositive(1.5f); // instantiated as float + + output[0] = (float)a + b + (float)c + d; +}