diff --git a/tools/clang/include/clang/Basic/DiagnosticParseKinds.td b/tools/clang/include/clang/Basic/DiagnosticParseKinds.td index 0fe0d22bbf..e328393726 100644 --- a/tools/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -994,8 +994,6 @@ def err_hlsl_unsupported_member_default : Error< "struct/class members cannot have default values">; def err_hlsl_unsupported_packoffset_component : Error< "packoffset component should indicate offset with one of x, y, z, w, r, g, b, or a">; -def err_hlsl_unsupported_pointer : Error< - "pointers are unsupported in HLSL">; def err_hlsl_unsupported_register_number : Error< "register number should be an integral numeric string">; def err_hlsl_unsupported_register_noninteger : Error< diff --git a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index eaffd4ee79..c35d14f7b2 100644 --- a/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8061,6 +8061,9 @@ def err_hlsl_linalg_attributed_matrix_required def err_hlsl_linalg_unsupported_stage : Error< "builtin unavailable in shader stage '%0' (requires 'compute', 'mesh' or 'amplification')">; +def err_hlsl_pointers_unsupported : Error< + "%select{pointers|references}0 are unsupported in HLSL">; + // HLSL Change Ends // SPIRV Change Starts diff --git a/tools/clang/lib/Parse/ParseDecl.cpp b/tools/clang/lib/Parse/ParseDecl.cpp index 6cfd498226..c91c8940a4 100644 --- a/tools/clang/lib/Parse/ParseDecl.cpp +++ b/tools/clang/lib/Parse/ParseDecl.cpp @@ -5887,15 +5887,6 @@ void Parser::ParseDeclaratorInternal(Declarator &D, return; } - // HLSL Change Starts - No pointer support in HLSL. - if (getLangOpts().HLSL) { - Diag(Tok, diag::err_hlsl_unsupported_pointer); - D.SetIdentifier(0, Tok.getLocation()); - D.setInvalidType(); - return; - } - // HLSL Change Ends - SourceLocation Loc = ConsumeToken(); D.SetRangeEnd(Loc); DeclSpec DS(AttrFactory); @@ -5917,12 +5908,6 @@ void Parser::ParseDeclaratorInternal(Declarator &D, tok::TokenKind Kind = Tok.getKind(); - // HLSL Change Starts - HLSL doesn't support pointers, references or blocks - if (getLangOpts().HLSL && isPtrOperatorToken(Kind, getLangOpts(), D.getContext())) { - Diag(Tok, diag::err_hlsl_unsupported_pointer); - } - // HLSL Change Ends - // Not a pointer, C++ reference, or block. if (!isPtrOperatorToken(Kind, getLangOpts(), D.getContext())) { if (DirectDeclParser) diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 7df68f5a11..127733e71e 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -15474,6 +15474,24 @@ bool Sema::DiagnoseHLSLDecl(Declarator &D, DeclContext *DC, Expr *BitWidth, if (!isFunction) hlslSource->WarnMinPrecision(qt, D.getLocStart()); + // HLSL Change Starts - disallow pointers through __decltype. + if (!D.isInvalidType() && pType && !qt->isDependentType()) { + if (const auto *DTT = dyn_cast(pType)) { + QualType Underlying = DTT->getUnderlyingType(); + if (Underlying->isPointerType()) { + Diag(D.getLocStart(), diag::err_hlsl_pointers_unsupported) << 0; + D.setInvalidType(); + return false; + } + if (Underlying->isReferenceType()) { + Diag(D.getLocStart(), diag::err_hlsl_pointers_unsupported) << 1; + D.setInvalidType(); + return false; + } + } + } + // HLSL Change Ends + // Early checks - these are not simple attribution errors, but constructs that // are fundamentally unsupported, // and so we avoid errors that might indicate they can be repaired. diff --git a/tools/clang/lib/Sema/SemaTemplate.cpp b/tools/clang/lib/Sema/SemaTemplate.cpp index 37b296aefd..b5945017da 100644 --- a/tools/clang/lib/Sema/SemaTemplate.cpp +++ b/tools/clang/lib/Sema/SemaTemplate.cpp @@ -421,8 +421,14 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope = nullptr; // HLSL Change begin - This is a reference. + // In HLSL, 'this' is an lvalue reference (not a pointer), so implicit + // member accesses use '.' (IsArrow=false). The base type must be the + // class type T, not the pointer type T*. + QualType MemberBaseType = + getLangOpts().HLSL ? ThisType->getPointeeType() : ThisType; return CXXDependentScopeMemberExpr::Create( - Context, /*This*/ nullptr, ThisType, /*IsArrow*/ !getLangOpts().HLSL, + Context, /*This*/ nullptr, MemberBaseType, + /*IsArrow*/ !getLangOpts().HLSL, /*Op*/ SourceLocation(), SS.getWithLocInContext(Context), TemplateKWLoc, FirstQualifierInScope, NameInfo, TemplateArgs); // HLSL Change end - This is a reference. diff --git a/tools/clang/lib/Sema/SemaType.cpp b/tools/clang/lib/Sema/SemaType.cpp index 52c55df6ae..7465cc2cec 100644 --- a/tools/clang/lib/Sema/SemaType.cpp +++ b/tools/clang/lib/Sema/SemaType.cpp @@ -1849,6 +1849,13 @@ QualType Sema::BuildPointerType(QualType T, return QualType(); } + // HLSL Change Begin - Disallow pointers. + if (getLangOpts().HLSL && Loc.isValid()) { + Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0; + return QualType(); + } + // HLSL Change End. + if (checkQualifiedFunction(*this, T, Loc, QFK_Pointer)) return QualType(); @@ -1911,6 +1918,13 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, return QualType(); } + // HLSL Change Begin - Disallow references. + if (getLangOpts().HLSL && Loc.isValid()) { + Diag(Loc, diag::err_hlsl_pointers_unsupported) << 1; + return QualType(); + } + // HLSL Change End. + if (checkQualifiedFunction(*this, T, Loc, QFK_Reference)) return QualType(); @@ -2313,6 +2327,13 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, return QualType(); } + // HLSL Change Begin - Disallow pointers. + if (getLangOpts().HLSL && Loc.isValid()) { + Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0; + return QualType(); + } + // HLSL Change End. + // Adjust the default free function calling convention to the default method // calling convention. if (T->isFunctionType()) diff --git a/tools/clang/lib/Sema/TreeTransform.h b/tools/clang/lib/Sema/TreeTransform.h index 2d2e692cd4..ef3a83c988 100644 --- a/tools/clang/lib/Sema/TreeTransform.h +++ b/tools/clang/lib/Sema/TreeTransform.h @@ -9852,7 +9852,12 @@ TreeTransform::TransformCXXDependentScopeMemberExpr( } else { OldBase = nullptr; BaseType = getDerived().TransformType(E->getBaseType()); - ObjectType = BaseType->getPointeeType(); + // HLSL Change - Begin + // In HLSL, 'this' is an lvalue reference so implicit member accesses use + // '.' (IsArrow=false) and the stored base type IS the object type, not a + // pointer to it. + ObjectType = E->isArrow() ? BaseType->getPointeeType() : BaseType; + // HLSL Change - End } // Transform the first part of the nested-name-specifier that qualifies diff --git a/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl b/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl index e792a702c2..57c512741c 100644 --- a/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl +++ b/tools/clang/test/HLSL/cpp-errors-hv2015.hlsl @@ -94,10 +94,10 @@ typename typedef float4 TFloat4; // expected-error {{'typename' is a reserved ke class C { int fn_eq_default() = default; // expected-error {{function deletion and defaulting is unsupported in HLSL}} - // Errors are a bit misleading here, but ultimate we don't support these. - void* operator new(); // expected-error {{'operator' is a reserved keyword in HLSL}} expected-error {{pointers are unsupported in HLSL}} - void* operator new(int); // expected-error {{'operator' is a reserved keyword in HLSL}} expected-error {{pointers are unsupported in HLSL}} - void* operator new(size_t); // expected-error {{'operator' is a reserved keyword in HLSL}} expected-error {{pointers are unsupported in HLSL}} + // Pointer return type is no longer caught at parse time; operator keyword error is still reported. + void* operator new(); // expected-error {{'operator' is a reserved keyword in HLSL}} + void* operator new(int); // expected-error {{'operator' is a reserved keyword in HLSL}} + void* operator new(size_t); // expected-error {{'operator' is a reserved keyword in HLSL}} C() = delete; // expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{constructor cannot have a return type}} }; diff --git a/tools/clang/test/HLSL/cpp-errors.hlsl b/tools/clang/test/HLSL/cpp-errors.hlsl index ac9630d9d7..bee34d249b 100644 --- a/tools/clang/test/HLSL/cpp-errors.hlsl +++ b/tools/clang/test/HLSL/cpp-errors.hlsl @@ -91,10 +91,10 @@ typename typedef float4 TFloat4; // expected-error {{'typename' is a reserved ke class C { int fn_eq_default() = default; // expected-error {{function deletion and defaulting is unsupported in HLSL}} - // Errors are a bit misleading here, but ultimate we don't support these. - void* operator new(); // expected-error {{'operator' is a reserved keyword in HLSL}} expected-error {{pointers are unsupported in HLSL}} - void* operator new(int); // expected-error {{'operator' is a reserved keyword in HLSL}} expected-error {{pointers are unsupported in HLSL}} - void* operator new(size_t); // expected-error {{'operator' is a reserved keyword in HLSL}} expected-error {{pointers are unsupported in HLSL}} + // Pointer return type is no longer caught at parse time; operator keyword error is still reported. + void* operator new(); // expected-error {{'operator' is a reserved keyword in HLSL}} + void* operator new(int); // expected-error {{'operator' is a reserved keyword in HLSL}} + void* operator new(size_t); // expected-error {{'operator' is a reserved keyword in HLSL}} C() = delete; // expected-error {{HLSL requires a type specifier for all declarations}} expected-error {{constructor cannot have a return type}} }; diff --git a/tools/clang/test/SemaHLSL/decltype-ptr-ref-instance-vars.hlsl b/tools/clang/test/SemaHLSL/decltype-ptr-ref-instance-vars.hlsl new file mode 100644 index 0000000000..2b12371598 --- /dev/null +++ b/tools/clang/test/SemaHLSL/decltype-ptr-ref-instance-vars.hlsl @@ -0,0 +1,67 @@ +// RUN: %dxc -Tlib_6_3 -Wno-unused-value -verify %s +// RUN: %dxc -Tcs_6_0 -Wno-unused-value -verify %s + +// Verify that pointer and reference types produced by __decltype cannot be +// used as struct instance variable types or local variable types in HLSL. +// Also verifies that template instantiation with pointer/reference type +// arguments is rejected, and that valid __decltype uses are not affected. + +// __decltype is the GCC way of saying 'decltype', but doesn't require C++11. + +// groupshared variables are mutable (unlike plain global variables in HLSL), +// which allows their lvalue expressions to produce reference types via +// __decltype. +groupshared int g; + +// --- Struct field: reference type from __decltype --- +struct RefField { + __decltype(++g) ref_field; // expected-error {{references are unsupported in HLSL}} +}; + +// --- Struct field: pointer type via explicit cast in __decltype --- +struct PtrField { + __decltype((int *)0) ptr_field; // expected-error {{pointers are unsupported in HLSL}} +}; + +// --- Struct field: plain (non-reference) type from __decltype is valid --- +struct PlainField { + __decltype(0 + 1) plain_field; // no error: int rvalue, not a reference +}; + +// --- Local variable: reference type from __decltype --- +void test_local_ref() { + int x = 0; + __decltype(++x) local_ref; // expected-error {{references are unsupported in HLSL}} +} + +// --- Local variable: pointer type via __decltype --- +void test_local_ptr() { + __decltype((int *)0) local_ptr; // expected-error {{pointers are unsupported in HLSL}} +} + +// --- Template: field with explicit reference type is rejected at definition --- +template +struct RefContainer { + T &ref_field; // expected-error {{references are unsupported in HLSL}} +}; + +// --- Template instantiation: type argument is an explicit pointer type --- +// This verifies that pointer instance variables cannot be created through +// template instantiation with pointer type arguments. +template +struct Container { + T field; +}; + +void test_template_ptr_explicit() { + Container c; // expected-error {{pointers are unsupported in HLSL}} +} + +// --- Regression: __decltype in is_same template argument still works --- +// HLSL has a non-standard is_same extension that treats T and T& as the same +// type. This is used in scalar-operators tests and must not be broken. +void test_is_same_regression() { + int x = 0; + _Static_assert(std::is_same::value, + "regression: is_same with lvalue __decltype must still work"); +} diff --git a/tools/clang/test/SemaHLSL/more-operators.hlsl b/tools/clang/test/SemaHLSL/more-operators.hlsl index cbd0250fb9..ed449051b6 100644 --- a/tools/clang/test/SemaHLSL/more-operators.hlsl +++ b/tools/clang/test/SemaHLSL/more-operators.hlsl @@ -276,25 +276,25 @@ float4 plain(float4 param4 /* : FOO */) /*: FOO */{ _Static_assert(std::is_same::value, ""); (--bool_l); // expected-error {{operator cannot be used with a bool lvalue}} fxc-error {{X3020: operator cannot be used with a bool lvalue}} (bool_l--); // expected-error {{operator cannot be used with a bool lvalue}} fxc-error {{X3020: operator cannot be used with a bool lvalue}} - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); // fxc-pass {{}} - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); // fxc-pass {{}} - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); (--SamplerState_l); // expected-error {{scalar, vector, or matrix expected}} fxc-pass {{}} (SamplerState_l--); // expected-error {{scalar, vector, or matrix expected}} fxc-pass {{}} @@ -306,39 +306,39 @@ float4 plain(float4 param4 /* : FOO */) /*: FOO */{ (bool1_l--); // expected-error {{operator cannot be used with a bool lvalue}} fxc-error {{X3020: operator cannot be used with a bool lvalue}} (--bool2_l); // expected-error {{operator cannot be used with a bool lvalue}} fxc-error {{X3020: operator cannot be used with a bool lvalue}} (bool2_l--); // expected-error {{operator cannot be used with a bool lvalue}} fxc-error {{X3020: operator cannot be used with a bool lvalue}} - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); /* fxc-pass {{}} */ - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); (++bool_l); // expected-error {{operator cannot be used with a bool lvalue}} fxc-error {{X3020: operator cannot be used with a bool lvalue}} (bool_l++); // expected-error {{operator cannot be used with a bool lvalue}} fxc-error {{X3020: operator cannot be used with a bool lvalue}} - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); // fxc-pass {{}} - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); // fxc-pass {{}} - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); (++SamplerState_l); // expected-error {{scalar, vector, or matrix expected}} fxc-pass {{}} (SamplerState_l++); // expected-error {{scalar, vector, or matrix expected}} fxc-pass {{}} @@ -350,17 +350,17 @@ float4 plain(float4 param4 /* : FOO */) /*: FOO */{ (bool1_l++); // expected-error {{operator cannot be used with a bool lvalue}} fxc-error {{X3020: operator cannot be used with a bool lvalue}} (++bool2_l); // expected-error {{operator cannot be used with a bool lvalue}} fxc-error {{X3020: operator cannot be used with a bool lvalue}} (bool2_l++); // expected-error {{operator cannot be used with a bool lvalue}} fxc-error {{X3020: operator cannot be used with a bool lvalue}} - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); /* fxc-pass {{}} */ - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); - _Static_assert(std::is_same::value, ""); // expected-error {{pointers are unsupported in HLSL}} fxc-pass {{}} + _Static_assert(std::is_same::value, ""); // expected-error {{references are unsupported in HLSL}} fxc-pass {{}} _Static_assert(std::is_same::value, ""); // Tests with multidimensional arrays. diff --git a/tools/clang/test/SemaHLSL/overloading-new-delete-errors.hlsl b/tools/clang/test/SemaHLSL/overloading-new-delete-errors.hlsl index ed68ecc4d9..c22e97479c 100644 --- a/tools/clang/test/SemaHLSL/overloading-new-delete-errors.hlsl +++ b/tools/clang/test/SemaHLSL/overloading-new-delete-errors.hlsl @@ -7,16 +7,16 @@ struct S { float foo; - void * operator new(int size) { // expected-error {{overloading 'operator new' is not allowed}} expected-error {{pointers are unsupported in HLSL}} - return (void *)0; // expected-error {{pointers are unsupported in HLSL}} expected-error {{cannot convert from 'literal int' to 'void *'}} expected-warning {{'operator new' should not return a null pointer unless it is declared 'throw()'}} + S operator new(int size) { // expected-error {{overloading 'operator new' is not allowed}} + return (S)0; } - void operator delete(void *ptr) { // expected-error {{overloading 'operator delete' is not allowed}} expected-error {{pointers are unsupported in HLSL}} + void operator delete(int ptr) { // expected-error {{overloading 'operator delete' is not allowed}} (void) ptr; } }; [shader("vertex")] void main() { - S *a = new S(); // expected-error {{'new' is a reserved keyword in HLSL}} expected-error {{pointers are unsupported in HLSL}} + S a = new S(); // expected-error {{'new' is a reserved keyword in HLSL}} delete a; // expected-error {{'delete' is a reserved keyword in HLSL}} } diff --git a/tools/clang/test/SemaHLSL/template-implicit-this-sfinae.hlsl b/tools/clang/test/SemaHLSL/template-implicit-this-sfinae.hlsl new file mode 100644 index 0000000000..9c9d43798e --- /dev/null +++ b/tools/clang/test/SemaHLSL/template-implicit-this-sfinae.hlsl @@ -0,0 +1,65 @@ +// RUN: %dxc -T cs_6_0 %s 2>&1 | FileCheck %s --check-prefix=COMPILE +// RUN: %dxc -T cs_6_0 -ast-dump %s 2>&1 | FileCheck %s + +// Test that template instantiation of member functions with SFINAE patterns +// involving static const members (accessed via implicit 'this') does not +// assert or crash. In HLSL, 'this' is an lvalue reference (not a pointer), +// so CXXDependentScopeMemberExpr must store the class type T (not T*) as the +// base type to avoid HLSL's ban on pointer types during template instantiation. + +namespace hlsl { +template struct enable_if {}; +template struct enable_if { + using type = T; +}; +template struct is_arithmetic { + static const bool value = false; +}; +template <> struct is_arithmetic { + static const bool value = true; +}; +template <> struct is_arithmetic { + static const bool value = true; +}; +} // namespace hlsl + +template +struct Wrapper { + static const bool IsArithmetic = hlsl::is_arithmetic::value; + + // SFINAE on a static const bool member accessed via implicit 'this'. + // This pattern previously triggered an assert when built with + // LLVM_ENABLE_ASSERTIONS=ON because template instantiation tried to rebuild + // the implicit 'this' pointer type, which is illegal in HLSL. + template + typename hlsl::enable_if::type Get() { + return val; + } + + T val; +}; + +// Verify that in the uninstantiated template the implicit 'this' is an lvalue +// of the class type (not a pointer), so HLSL's pointer ban is not violated. +// CHECK: CXXThisExpr {{.*}} 'Wrapper' lvalue this + +// Verify the same holds in the Wrapper instantiation's Get method. +// CHECK: CXXThisExpr {{.*}} 'Wrapper' lvalue this + +// Verify the same holds in the Wrapper instantiation's Get method. +// CHECK: CXXThisExpr {{.*}} 'Wrapper' lvalue this + +// Verify no CXXThisExpr carries a pointer type for 'this'. +// CHECK-NOT: CXXThisExpr {{.*}} '{{[^']*}} \*' lvalue this + +// COMPILE: define void @main +[numthreads(1, 1, 1)] +void main() { + Wrapper wf; + wf.val = 1.0f; + float f = wf.Get(); + + Wrapper wi; + wi.val = 2; + int i = wi.Get(); +}