Skip to content
Merged
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
3 changes: 3 additions & 0 deletions docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ line upon naming the release. Refer to previous for appropriate section names.
- HLSL 202x now supports variadic templates and template function parameter
packs, pack expansions, and `sizeof...()`
[#8905](https://github.com/microsoft/DirectXShaderCompiler/issues/8905).
- HLSL 202x disallows initializers on variables in explicit and implicit
constant buffers and texture buffers
[#8483](https://github.com/microsoft/DirectXShaderCompiler/issues/8483).
- HLSL 202x disallows putting cbuffer, tbuffer, or namespace declarations inside
a cbuffer or tbuffer
[#8484](https://github.com/microsoft/DirectXShaderCompiler/issues/8484).
Expand Down
3 changes: 3 additions & 0 deletions tools/clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,9 @@ def HLSLParameterUsage : DiagGroup<"parameter-usage">;
def HLSLAvailability: DiagGroup<"hlsl-availability">;
def HLSLAvailabilityConstant: DiagGroup<"hlsl-availability-constant">;
def HLSLBarrier : DiagGroup<"hlsl-barrier">;
def HLSLBufferInitializer : DiagGroup<"hlsl-buffer-initializer">;
def HLSLGroupSharedInitializer :
DiagGroup<"hlsl-groupshared-initializer">;

// HLSL 2026 compatibility warnings: these warn on code in older language modes
// that changes meaning or becomes illegal in HLSL 2026.
Expand Down
8 changes: 8 additions & 0 deletions tools/clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -7575,6 +7575,14 @@ def err_hlsl_packoffset_requires_cbuffer : Error<
"packoffset is only allowed in a constant buffer">;
def warn_hlsl_packoffset_mix : Warning<
"cannot mix packoffset elements with nonpackoffset elements in a cbuffer">;
def warn_hlsl_buffer_initializer : Warning<
"initializer for a variable in a %select{tbuffer|cbuffer}0 will be ignored">,
InGroup<HLSLBufferInitializer>;
def err_hlsl_buffer_initializer : Error<
"variable in a %select{tbuffer|cbuffer}0 cannot have an initializer">;
def warn_hlsl_groupshared_initializer : Warning<
"initializer of 'groupshared' variable will be ignored">,
InGroup<HLSLGroupSharedInitializer>;
def err_hlsl_packoffset_overlap : Error<"packoffset overlap between %0, %1">;
def err_hlsl_register_semantics_conflicting : Error<
"conflicting register semantics">;
Expand Down
14 changes: 2 additions & 12 deletions tools/clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2109,12 +2109,6 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
NeedsGlobalCtor = true;
// HLSL Change Begins.
if (getLangOpts().HLSL && D->isExternallyVisible()) {
// For global constant with init, the init will be ignored.
// Warning here.
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Warning,
"Initializer of external global will be ignored");
Diags.Report(D->getLocation(), DiagID);
// Don't create global ctor for it.
NeedsGlobalCtor = false;
}
Expand All @@ -2130,13 +2124,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
if (getLangOpts().CPlusPlus && !NeedsGlobalDtor)
DelayedCXXInitPosition.erase(D);
// HLSL Change Begins.
if (getLangOpts().HLSL && D->isExternallyVisible() && !D->isStaticDataMember()) {
// For global constant with init, the init will be ignored.
if (getLangOpts().HLSL && D->isExternallyVisible() &&
!D->isStaticDataMember()) {
Init = EmitNullConstant(D->getType());
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Warning,
"Initializer of external global will be ignored");
Diags.Report(D->getLocation(), DiagID);
}
// HLSL Change Ends.
}
Expand Down
7 changes: 0 additions & 7 deletions tools/clang/lib/SPIRV/DeclResultIdMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1780,13 +1780,6 @@ void DeclResultIdMapper::createGlobalsCBuffer(const VarDecl *var) {
uint32_t index = 0;
for (const auto *decl : collectDeclsInDeclContext(context)) {
if (const auto *varDecl = dyn_cast<VarDecl>(decl)) {
if (!spirvOptions.noWarnIgnoredFeatures) {
if (const auto *init = varDecl->getInit())
emitWarning(
"variable '%0' will be placed in $Globals so initializer ignored",
init->getExprLoc())
<< var->getName() << init->getSourceRange();
}
if (const auto *attr = varDecl->getAttr<VKBindingAttr>()) {
emitError("variable '%0' will be placed in $Globals so cannot have "
"vk::binding attribute",
Expand Down
14 changes: 0 additions & 14 deletions tools/clang/lib/SPIRV/SpirvEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1937,21 +1937,11 @@ void SpirvEmitter::registerCapabilitiesAndExtensionsForVarDecl(

void SpirvEmitter::doHLSLBufferDecl(const HLSLBufferDecl *bufferDecl) {
// This is a cbuffer/tbuffer decl.
// Check and emit warnings for member intializers which are not
// supported in Vulkan
for (const auto *member : bufferDecl->decls()) {
if (const auto *varMember = dyn_cast<VarDecl>(member)) {
if (varMember->getStorageClass() == StorageClass::SC_Static)
continue;

if (!spirvOptions.noWarnIgnoredFeatures) {
if (const auto *init = varMember->getInit())
emitWarning("%select{tbuffer|cbuffer}0 member initializer "
"ignored since no Vulkan equivalent",
init->getExprLoc())
<< bufferDecl->isCBuffer() << init->getSourceRange();
}

// We cannot handle external initialization of column-major matrices now.
if (isOrContainsNonFpColMajorMatrix(astContext, spirvOptions,
varMember->getType(), varMember)) {
Expand Down Expand Up @@ -2199,10 +2189,6 @@ void SpirvEmitter::doVarDecl(const VarDecl *decl) {
// variables) belongs to the Function storage class.
if (isExternalVar(decl)) {
var = declIdMapper.createExternVar(decl);
if (decl->hasInit()) {
emitWarning("Initializer of external global will be ignored",
decl->getLocation());
}
} else {
// We already know the variable is not externally visible here. If it does
// not have local storage, it should be file scope variable.
Expand Down
44 changes: 44 additions & 0 deletions tools/clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,28 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) {

namespace {

// HLSL Change Begin
// Returns true if VD is a shader constant: a variable stored in an explicit
// cbuffer/tbuffer declaration, or in the implicit $Globals constant buffer.
// On success IsConstantBuffer is false only for tbuffer members.
bool IsHLSLShaderConstant(const VarDecl *VD, bool &IsConstantBuffer) {
if (const auto *Buffer = dyn_cast<HLSLBufferDecl>(VD->getDeclContext())) {
IsConstantBuffer = Buffer->isCBuffer();
return VD->getStorageClass() != SC_Static;
}

IsConstantBuffer = true;
const DeclContext *DC = VD->getDeclContext();
return (DC->isTranslationUnit() || DC->isNamespace()) &&
VD->hasExternalFormalLinkage() &&
!VD->hasAttr<HLSLGroupSharedAttr>() &&
Comment thread
Copilot marked this conversation as resolved.
!VD->hasAttr<VKConstantIdAttr>() &&
!VD->hasAttr<VKPushConstantAttr>() &&
!VD->hasAttr<VKStorageClassExtAttr>() &&
hlsl::IsHLSLNumericOrAggregateOfNumericType(VD->getType());
}
// HLSL Change End

class TypeNameValidatorCCC : public CorrectionCandidateCallback {
public:
TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false,
Expand Down Expand Up @@ -9334,6 +9356,28 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// Attach the initializer to the decl.
VDecl->setInit(Init);

// HLSL Change Begin
if (getLangOpts().HLSL) {
if (VDecl->hasAttr<HLSLGroupSharedAttr>() &&
(getLangOpts().SPIRV || VDecl->isExternallyVisible())) {
Diag(Init->getExprLoc(), diag::warn_hlsl_groupshared_initializer)
<< Init->getSourceRange();
} else {
// Variables in a cbuffer/tbuffer declaration, or in the implicit
// $Globals constant buffer, are initialized by the pipeline, so any
// initializer is ignored. This is an error starting with HLSL 202x.
bool IsConstantBuffer = false;
if (IsHLSLShaderConstant(VDecl, IsConstantBuffer)) {
Diag(Init->getExprLoc(),
getLangOpts().HLSLVersion >= hlsl::LangStd::v202x
? diag::err_hlsl_buffer_initializer
: diag::warn_hlsl_buffer_initializer)
<< IsConstantBuffer << Init->getSourceRange();
}
}
}
// HLSL Change End

if (VDecl->isLocalVarDecl()) {
// C99 6.7.8p4: All the expressions in an initializer for an object that has
// static storage duration shall be constant expressions or string literals.
Expand Down
11 changes: 6 additions & 5 deletions tools/clang/test/CodeGenSPIRV/groupshared.init.warning.hlsl
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
// RUN: %dxc -T cs_6_0 -E main -spirv %s 2>&1 | FileCheck %s
// RUN: %dxc -T cs_6_0 -E main -spirv -verify %s

groupshared uint testing = 0;
// expected-warning@-1 {{initializer of 'groupshared' variable will be ignored}}

static groupshared uint staticTesting = 1;
// expected-warning@-1 {{initializer of 'groupshared' variable will be ignored}}

[numthreads(64, 1, 1)]
void main(uint local_thread_id_flat : SV_GroupIndex) {

InterlockedAdd(testing, 1);
InterlockedAdd(testing, staticTesting);
GroupMemoryBarrierWithGroupSync();

if (local_thread_id_flat == 0) {
Expand All @@ -14,6 +18,3 @@ void main(uint local_thread_id_flat : SV_GroupIndex) {
}
}
}

// CHECK: warning: Initializer of external global will be ignored
// CHECK-NEXT: groupshared uint testing = 0;
3 changes: 2 additions & 1 deletion tools/clang/test/CodeGenSPIRV/implicit.global.ubo.hlsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %dxc -T ps_6_0 -E main %s -spirv | FileCheck %s
// RUN: %dxc -T ps_6_0 -E main -Werror %s -spirv | FileCheck %s
// RUN: %dxc -T ps_6_0 -E main -HV 202x %s -spirv | FileCheck %s

// This test checks that the specialization constant and push constants are not
// included in the implicit global ubo.
Expand Down
7 changes: 4 additions & 3 deletions tools/clang/test/CodeGenSPIRV/var.globals.error.hlsl
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// RUN: not %dxc -T vs_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s

// Note: this test uses FileCheck instead of -verify because the error
// diagnostic comes from the code generation layer instead of sema.
[[vk::binding(10, 2)]] float4 gVec = 1.0;

float4 main() : A { return gVec; }

// CHECK: :3:38: warning: variable 'gVec' will be placed in $Globals so initializer ignored
// CHECK: :3:3: error: variable 'gVec' will be placed in $Globals so cannot have vk::binding attribute
// CHECK: :4:38: warning: initializer for a variable in a cbuffer will be ignored
// CHECK: :4:3: error: variable 'gVec' will be placed in $Globals so cannot have vk::binding attribute
9 changes: 3 additions & 6 deletions tools/clang/test/CodeGenSPIRV/var.init.cbuffer.hlsl
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
// RUN: %dxc -T vs_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s
// RUN: %dxc -T vs_6_0 -E main -verify %s -spirv

cbuffer MyCBuffer {
float a = 1.0;
float4 b = 2.0;
float a = 1.0; // expected-warning{{initializer for a variable in a cbuffer will be ignored}}
float4 b = 2.0; // expected-warning{{initializer for a variable in a cbuffer will be ignored}}
};

float main() : A {
return 1.0;
}

// CHECK: :4:15: warning: cbuffer member initializer ignored since no Vulkan equivalent
// CHECK: :5:16: warning: cbuffer member initializer ignored since no Vulkan equivalent
9 changes: 3 additions & 6 deletions tools/clang/test/CodeGenSPIRV/var.init.tbuffer.hlsl
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
// RUN: %dxc -T vs_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s
// RUN: %dxc -T vs_6_0 -E main -verify %s -spirv

tbuffer MyTBuffer {
float a = 1.0;
float4 b = 2.0;
float a = 1.0; //expected-warning{{initializer for a variable in a tbuffer will be ignored}}
float4 b = 2.0; //expected-warning{{initializer for a variable in a tbuffer will be ignored}}
};

float main() : A {
return 1.0;
}

// CHECK: :4:15: warning: tbuffer member initializer ignored since no Vulkan equivalent
// CHECK: :5:16: warning: tbuffer member initializer ignored since no Vulkan equivalent
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %dxc -T vs_6_0 -E main -Wno-vk-ignored-features -fcgl %s -spirv 2>&1 | FileCheck %s
// RUN: %dxc -T vs_6_0 -E main -Wno-vk-ignored-features -Wno-hlsl-buffer-initializer -fcgl %s -spirv 2>&1 | FileCheck %s

cbuffer MyCBuffer {
float a = 1.0;
Expand Down
2 changes: 1 addition & 1 deletion tools/clang/test/HLSL/cpp-errors-hv2015.hlsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -HV 2015 -fsyntax-only -Wno-unused-value -ffreestanding -verify %s
// RUN: %clang_cc1 -Wno-hlsl-buffer-initializer -HV 2015 -fsyntax-only -Wno-unused-value -ffreestanding -verify %s

float f_arr_empty_init[] = { 1, 2, 3 };
float f_arr_empty_pack[] = { 1, 2 ... }; // expected-error {{expansion is unsupported in HLSL}}
Expand Down
12 changes: 6 additions & 6 deletions tools/clang/test/HLSL/cpp-errors.hlsl
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -ffreestanding -HV 2018 -verify %s

float f_arr_empty_init[] = { 1, 2, 3 };
float f_arr_empty_init[] = { 1, 2, 3 }; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */
float f_arr_empty_pack[] = { 1, 2 ... }; // expected-error {{expansion is unsupported in HLSL}}

struct s_arr_i_f { int i; float f; };
s_arr_i_f arr_struct_none[] = { }; // TODO: this should fail - see comments in HLSLExternalSource::InitializeInitSequenceForHLSL
s_arr_i_f arr_struct_one[] = { 1, 2 };
s_arr_i_f arr_struct_none[] = { }; // TODO: this should fail - see comments in HLSLExternalSource::InitializeInitSequenceForHLSL /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */
s_arr_i_f arr_struct_one[] = { 1, 2 }; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */
s_arr_i_f arr_struct_incomplete[] = { 1, 2, 3 }; // expected-error {{too few elements in vector initialization (expected 4 elements, have 3)}}
s_arr_i_f arr_struct_two[] = { 1, 2, 3, 4 };
s_arr_i_f arr_struct_two[] = { 1, 2, 3, 4 }; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */

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; // auto is now supported in HLSL via type deduction; no error expected /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */
__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}}
Expand Down Expand Up @@ -321,7 +321,7 @@ struct forward_struct; // this fails in fxc, but we allow it now
struct my_struct_type_decl { int a; } my_struct_var_decl;
struct my_struct_type_decl_parens { int a; } (my_struct_var_decl_parens); // expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{expected ';' after struct}}
struct my_struct_type_const { int a; } const my_struct_type_var; // // expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{expected ';' after struct}}
struct my_struct_type_init { int a; } my_struct_type_init_one = { 1 }, my_struct_type_init_two = { 2 };
struct my_struct_type_init { int a; } my_struct_type_init_one = { 1 }, my_struct_type_init_two = { 2 }; /* expected-warning 2 {{initializer for a variable in a cbuffer will be ignored}} */
struct my_struct_type_static { int a; } static my_struct_type_static; // expected-error {{expected ';' after struct}} expected-warning {{declaration does not declare anything}}
struct { int my_anon_struct_field; } my_anon_struct_type;

Expand Down
10 changes: 5 additions & 5 deletions tools/clang/test/HLSL/rewriter/cpp-errors_noerr.hlsl
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -Wno-unused-value -ffreestanding -verify %s

float f_arr_empty_init[] = { 1, 2, 3 };
float f_arr_empty_init[] = { 1, 2, 3 }; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */
//float f_arr_empty_pack[] = { 1, 2 ... }; // expected-error {{expansion is unsupported in HLSL}}

struct s_arr_i_f { int i; float f; };
s_arr_i_f arr_struct_none[] = { }; // TODO: this should fail - see comments in HLSLExternalSource::InitializeInitSequenceForHLSL
s_arr_i_f arr_struct_one[] = { 1, 2 };
s_arr_i_f arr_struct_none[] = { }; // TODO: this should fail - see comments in HLSLExternalSource::InitializeInitSequenceForHLSL /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */
s_arr_i_f arr_struct_one[] = { 1, 2 }; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */
//s_arr_i_f arr_struct_incomplete[] = { 1, 2, 3 }; // expected-error {{too few elements in vector initialization (expected 4 elements, have 3)}}
s_arr_i_f arr_struct_two[] = { 1, 2, 3, 4 };
s_arr_i_f arr_struct_two[] = { 1, 2, 3, 4 }; /* expected-warning {{initializer for a variable in a cbuffer will be ignored}} */

int g_int;
//typeof(g_int) g_typeof_int; // expected-error {{unknown type name 'typeof'; did you mean 'typedef'?}} expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{expected ';' after top level declarator}}
Expand Down Expand Up @@ -332,7 +332,7 @@ struct my_struct_5 : my_class, my_interface { };
struct my_struct_type_decl { int a; } my_struct_var_decl;
//struct my_struct_type_decl_parens { int a; } (my_struct_var_decl_parens); // expected-error {{expected ';' after struct}} expected-error {{HLSL requires a type specifier for all declarations}}
//struct my_struct_type_const { int a; } const my_struct_type_var; // // expected-error {{expected ';' after struct}} expected-error {{HLSL requires a type specifier for all declarations}}
struct my_struct_type_init { int a; } my_struct_type_init_one = { 1 }, my_struct_type_init_two = { 2 };
struct my_struct_type_init { int a; } my_struct_type_init_one = { 1 }, my_struct_type_init_two = { 2 }; /* expected-warning 2 {{initializer for a variable in a cbuffer will be ignored}} */
//struct my_struct_type_static { int a; } static my_struct_type_static; // expected-error {{expected ';' after struct}} expected-warning {{declaration does not declare anything}}
struct { int my_anon_struct_field; } my_anon_struct_type;

Expand Down
Loading
Loading