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
2 changes: 0 additions & 2 deletions tools/clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
3 changes: 3 additions & 0 deletions tools/clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 0 additions & 15 deletions tools/clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand Down
18 changes: 18 additions & 0 deletions tools/clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<DecltypeType>(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.
Expand Down
8 changes: 7 additions & 1 deletion tools/clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
21 changes: 21 additions & 0 deletions tools/clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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())
Expand Down
7 changes: 6 additions & 1 deletion tools/clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -9852,7 +9852,12 @@ TreeTransform<Derived>::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
Expand Down
8 changes: 4 additions & 4 deletions tools/clang/test/HLSL/cpp-errors-hv2015.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
};
Expand Down
8 changes: 4 additions & 4 deletions tools/clang/test/HLSL/cpp-errors.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
};
Expand Down
67 changes: 67 additions & 0 deletions tools/clang/test/SemaHLSL/decltype-ptr-ref-instance-vars.hlsl
Original file line number Diff line number Diff line change
@@ -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 <typename T>
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 <typename T>
struct Container {
T field;
};

void test_template_ptr_explicit() {
Container<int *> 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<int, __decltype(x += 1)>::value,
"regression: is_same with lvalue __decltype must still work");
}
Loading
Loading