Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[HLSL] Add implicit resource element type concepts to AST #112600

Merged
merged 27 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ab60544
ConceptSpecializationExpr shows up in AST!!!
bob80905 Oct 10, 2024
b43675f
CSE is in the right spot in the AST
bob80905 Oct 10, 2024
4307e45
templateArg is aligned correctly on the AST
bob80905 Oct 11, 2024
4beb3a3
template arguments are in the right spot!
bob80905 Oct 15, 2024
98200c0
template arguments are almost done
bob80905 Oct 15, 2024
f70fb48
IT WORKS! updated template arg name, just need to remove extraneous t…
bob80905 Oct 15, 2024
54917b1
break down constraint expression into simpler function
bob80905 Oct 16, 2024
6ebe14a
remove useless function
bob80905 Oct 16, 2024
1ecd544
some variable renaming, function rearranging
bob80905 Oct 16, 2024
19664f5
clang format
bob80905 Oct 16, 2024
ea0ac08
fix / add test cases
bob80905 Oct 16, 2024
d220a73
add default nullptr, remove comments
bob80905 Oct 17, 2024
8014a47
remove unused var, use vector to extend memory lifetime, may need to …
bob80905 Oct 17, 2024
8516483
address everything
bob80905 Oct 18, 2024
defc84e
remove clang::, add c++ ast generation code, fix var names
bob80905 Oct 18, 2024
b373f15
undo formatting problem
bob80905 Oct 18, 2024
4fecdc4
get rid of clang:: specifier for enum values
bob80905 Oct 18, 2024
80d2d25
change some function names
bob80905 Oct 18, 2024
d770236
clang format
bob80905 Oct 18, 2024
1159b02
remove referenced, update tests
bob80905 Oct 31, 2024
cf1a7fd
address Chris
bob80905 Nov 5, 2024
17696d8
fix typo
bob80905 Nov 5, 2024
6edf031
address Helena
bob80905 Nov 7, 2024
fae51c5
address damyan, clarify comments
bob80905 Nov 7, 2024
1722578
nfc to kick off bots again
bob80905 Nov 8, 2024
f50b917
clarify comment, add concept AST test
bob80905 Nov 8, 2024
47f106b
use namespace decl as context
bob80905 Nov 13, 2024
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
217 changes: 205 additions & 12 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,9 @@ struct BuiltinTypeDeclBuilder {
}

TemplateParameterListBuilder addTemplateArgumentList(Sema &S);
BuiltinTypeDeclBuilder &addSimpleTemplateParams(Sema &S,
ArrayRef<StringRef> Names);
BuiltinTypeDeclBuilder &
addSimpleTemplateParams(Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD);
BuiltinTypeDeclBuilder &addConceptSpecializationExpr(Sema &S);
};

struct TemplateParameterListBuilder {
Expand All @@ -323,30 +324,127 @@ struct TemplateParameterListBuilder {
S.Context, Builder.Record->getDeclContext(), SourceLocation(),
SourceLocation(), /* TemplateDepth */ 0, Position,
&S.Context.Idents.get(Name, tok::TokenKind::identifier),
/* Typename */ false,
/* ParameterPack */ false);
/* Typename */ true,
/* ParameterPack */ false,
/* HasTypeConstraint*/ false);
if (!DefaultValue.isNull())
Decl->setDefaultArgument(
S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(),
SourceLocation()));

Params.emplace_back(Decl);
return *this;
}

BuiltinTypeDeclBuilder &finalizeTemplateArgs() {
/*
The concept specialization expression (CSE) constructed below is constructed
so that it matches the CSE that is constructed when parsing
the below C++ code:

template<typename T>
concept is_valid_line_vector =sizeof(T) <= 16;

template<typename element_type> requires is_valid_line_vector<element_type>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still uses the old name.


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The blank line between the template bit and the struct really confused me for a while trying to read this.

struct RWBuffer {
element_type Val;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that the code in this comment really matches the AST that's being built.

RWBuffer doesn't have a member of type element_type, for example.

I think that this function is just building up the AST that corresponds to the requires is_typed_resource_element_compatible<element_Type> part?

The AST nodes for template<typename T> concept is_typed_resource_element_compatible =sizeof(T) <= 16;
itself is created in constructTypedBufferConceptDecl?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that when parsing the C++ code in the comment, it produces more of the AST than the function is producing, but I still believe that including that extra context in the comments is helpful. The C++ code adds the structure "RWBuffer", and though it isn't being produced by constructConceptSpecializationExpr, it helps to know what code can be copy pasted into godbolt, for example, to see the AST that would be produced.
I had originally wanted to paste the AST that would be produced, but figured getting the source code would help explain the code better and also allow those who are interested to get the AST from the code.

The first point of the comment says that
"The concept specialization expression (CSE) constructed below is constructed
so that it matches the CSE that is constructed when parsing
the below C++ code:"
Which is still accurate. The code in the function isn't claiming to be responsible for the whole AST. I will reword it slightly for more clarity.

For your last 2 questions, yes I think your statements are accurate.

};

int fn() {
RWBuffer<int> Buf;
}

When dumping the AST and filtering for "RWBuffer", the resulting AST
structure is what we're trying to construct below, specifically the
CSE portion.
*/
ConceptSpecializationExpr *
constructConceptSpecializationExpr(Sema &S, ConceptDecl *CD) {
ASTContext &Context = S.getASTContext();
SourceLocation Loc = Builder.Record->getBeginLoc();
DeclarationNameInfo DNI(CD->getDeclName(), Loc);
NestedNameSpecifierLoc NNSLoc;
DeclContext *DC = Builder.Record->getDeclContext();
TemplateArgumentListInfo TALI(Loc, Loc);

// Assume that the concept decl has just one template parameter
// This parameter should have been added when CD was constructed
// in getTypedBufferConceptDecl
assert(CD->getTemplateParameters()->size() == 1 &&
"unexpected concept decl parameter count");
TemplateTypeParmDecl *ConceptTTPD = dyn_cast<TemplateTypeParmDecl>(
CD->getTemplateParameters()->getParam(0));

// this fake TemplateTypeParmDecl is used to construct a template argument
// that will be used to construct the ImplicitConceptSpecializationDecl
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's fake about it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't being placed into the AST, the sole reason for its existence is to allow a path to construct a TemplateArgument, and that TemplateArgument will actually be placed into the AST. The fake TemplateTypeParmDecl is otherwise unused and discarded.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds wrong... Like, completely wrong. You're absolutely adding it to the AST, that's what happens when you create a declaration and put it into a declaration context.

This also seems like we're putting this declaration into the wrong declaration context.

I don't see any of your tests verifying the AST shape of the concept declaration. Can you add tests for that so that we can see what the concept's AST looks like?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On further investigation, yes I believe it is being placed into the AST. I didn't realize that setting the DeclContext correlated with AST placement. However, comparing the generated AST with similar C++ code, I do think the declaration context for this template type parm decl is correct. (That is, the context is the ClassTemplateDecl, and it shows up directly indented under the ClassTemplateDecl in the AST.

I've added tests for the concept declaration AST.

TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
Context, // AST context
Context.getTranslationUnitDecl(), // DeclContext
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where the DeclContext is wrong that I referenced in https://github.com/llvm/llvm-project/pull/112600/files/6edf031b5e736b38cf3551ccc872351f9c8a07ca#r1835111011

Suggested change
Context.getTranslationUnitDecl(), // DeclContext
Builder.Record->getDeclContext();, // DeclContext

SourceLocation(), SourceLocation(),
/*depth=*/0, // Depth in the template parameter list
/*position=*/0, // Position in the template parameter list
/*id=*/nullptr, // Identifier for 'T'
/*Typename=*/true, // Indicates this is a 'typename' or 'class'
/*ParameterPack=*/false, // Not a parameter pack
/*HasTypeConstraint=*/false // Has no type constraint
);

T->setDeclContext(DC);
T->setReferenced();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to set this explicitly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting the decl context is necessary because it puts the decl into the right indentation in the AST dump. Otherwise, I believe the decl would be placed at the same scope as one indentation below the translation unit decl, which is not where the decl belongs.
I'll see if I can get away with removing setReferenced here.


QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD);

// this is the 2nd template argument node in the AST above
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure what "the AST above" refers to.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this was when I had the entire AST inside a comment previously, haven't updated it, will fix!

TemplateArgument ConceptTA = TemplateArgument(ConceptTType);

QualType CSETType = Context.getTypeDeclType(T);

// this is the 1st template argument node in the AST above
TemplateArgument CSETA = TemplateArgument(CSETType);

ImplicitConceptSpecializationDecl *ImplicitCSEDecl =
ImplicitConceptSpecializationDecl::Create(
Context, Builder.Record->getDeclContext(), Loc, {CSETA});

// Constraint satisfaction is used to construct the
// ConceptSpecailizationExpr, and represents the 2nd Template Argument,
// located at the bottom of the sample AST above.
const ConstraintSatisfaction CS(CD, {ConceptTA});
TemplateArgumentLoc TAL = S.getTrivialTemplateArgumentLoc(
ConceptTA, QualType(), SourceLocation());

TALI.addArgument(TAL);
const ASTTemplateArgumentListInfo *ATALI =
ASTTemplateArgumentListInfo::Create(Context, TALI);

// In the concept reference, ATALI is what adds the extra
// TemplateArgument node underneath CSE
ConceptReference *CR =
ConceptReference::Create(Context, NNSLoc, Loc, DNI, CD, CD, ATALI);

ConceptSpecializationExpr *CSE =
ConceptSpecializationExpr::Create(Context, CR, ImplicitCSEDecl, &CS);

return CSE;
}

BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD = nullptr) {
if (Params.empty())
return Builder;
ConceptSpecializationExpr *CSE =
CD ? constructConceptSpecializationExpr(S, CD) : nullptr;

auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(),
SourceLocation(), Params,
SourceLocation(), nullptr);
SourceLocation(), CSE);
Builder.Template = ClassTemplateDecl::Create(
S.Context, Builder.Record->getDeclContext(), SourceLocation(),
DeclarationName(Builder.Record->getIdentifier()), ParamList,
Builder.Record);

Builder.Record->setDescribedClassTemplate(Builder.Template);
Builder.Template->setImplicit(true);
Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());

// NOTE: setPreviousDecl before addDecl so new decl replace old decl when
// make visible.
Builder.Template->setPreviousDecl(Builder.PrevTemplate);
Expand All @@ -366,13 +464,13 @@ BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) {
return TemplateParameterListBuilder(S, *this);
}

BuiltinTypeDeclBuilder &
BuiltinTypeDeclBuilder::addSimpleTemplateParams(Sema &S,
ArrayRef<StringRef> Names) {
BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addSimpleTemplateParams(
Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD = nullptr) {
TemplateParameterListBuilder Builder = this->addTemplateArgumentList(S);
for (StringRef Name : Names)
Builder.addTypeParameter(Name);
return Builder.finalizeTemplateArgs();

return Builder.finalizeTemplateArgs(CD);
}

HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
Expand Down Expand Up @@ -483,10 +581,105 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
.addDefaultHandleConstructor(S, RC);
}

BinaryOperator *constructSizeOfLEQ16Expr(ASTContext &Context,
SourceLocation NameLoc,
TemplateTypeParmDecl *T) {
// Obtain the QualType for 'unsigned long'
QualType UnsignedLongType = Context.UnsignedLongTy;

// Create a QualType that points to this TemplateTypeParmDecl
QualType TType = Context.getTypeDeclType(T);

// Create a TypeSourceInfo for the template type parameter 'T'
TypeSourceInfo *TTypeSourceInfo =
Context.getTrivialTypeSourceInfo(TType, NameLoc);

UnaryExprOrTypeTraitExpr *sizeOfExpr = new (Context) UnaryExprOrTypeTraitExpr(
UETT_SizeOf, TTypeSourceInfo, UnsignedLongType, NameLoc, NameLoc);

// Create an IntegerLiteral for the value '16' with size type
QualType SizeType = Context.getSizeType();
llvm::APInt SizeValue = llvm::APInt(Context.getTypeSize(SizeType), 16);
IntegerLiteral *SizeLiteral =
new (Context) IntegerLiteral(Context, SizeValue, SizeType, NameLoc);

QualType BoolTy = Context.BoolTy;

BinaryOperator *binaryOperator =
BinaryOperator::Create(Context, sizeOfExpr, // Left-hand side expression
SizeLiteral, // Right-hand side expression
BO_LE, // Binary operator kind (<=)
BoolTy, // Result type (bool)
VK_LValue, // Value kind
OK_Ordinary, // Object kind
NameLoc, // Source location of operator
FPOptionsOverride());

return binaryOperator;
}

Expr *constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
TemplateTypeParmDecl *T) {
ASTContext &Context = S.getASTContext();

// first get the "sizeof(T) <= 16" expression, as a binary operator
BinaryOperator *SizeOfLEQ16 = constructSizeOfLEQ16Expr(Context, NameLoc, T);
// TODO: add the 'builtin_hlsl_is_typed_resource_element_compatible' builtin
// and return a binary operator that evaluates the builtin on the given
// template type parameter 'T'.
// Defined in issue https://github.com/llvm/llvm-project/issues/113223
return SizeOfLEQ16;
}

ConceptDecl *constructTypedBufferConceptDecl(Sema &S, NamespaceDecl *NSD) {
ASTContext &Context = S.getASTContext();
DeclContext *DC = NSD->getDeclContext();
SourceLocation DeclLoc = SourceLocation();

IdentifierInfo &IsTypedResourceElementCompatibleII =
Context.Idents.get("__is_typed_resource_element_compatible");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit - move this just before DeclName declaration, or better yet use Context.Idents.get("__is_typed_resource_element_compatible") directly in the DeclarationName constructor.
It makes it easier to read when variables are declared closer to where they are is used.

IdentifierInfo &ElementTypeII = Context.Idents.get("element_type");
TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
Context, Context.getTranslationUnitDecl(), DeclLoc, DeclLoc,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure this is also wrong here:

Suggested change
Context, Context.getTranslationUnitDecl(), DeclLoc, DeclLoc,
Context, NSD->getDeclContext(), DeclLoc, DeclLoc,

/*depth=*/0,
/*position=*/0,
/*id=*/&ElementTypeII,
/*Typename=*/true,
/*ParameterPack=*/false);

T->setDeclContext(DC);
T->setReferenced();

// Create and Attach Template Parameter List to ConceptDecl
TemplateParameterList *ConceptParams = TemplateParameterList::Create(
Context, DeclLoc, DeclLoc, {T}, DeclLoc, nullptr);

DeclarationName DeclName =
DeclarationName(&IsTypedResourceElementCompatibleII);
Expr *ConstraintExpr = constructTypedBufferConstraintExpr(S, DeclLoc, T);

// Create a ConceptDecl
ConceptDecl *CD =
ConceptDecl::Create(Context, Context.getTranslationUnitDecl(), DeclLoc,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ConceptDecl::Create(Context, Context.getTranslationUnitDecl(), DeclLoc,
ConceptDecl::Create(Context, NSD->getDeclContext(), DeclLoc,

DeclName, ConceptParams, ConstraintExpr);

// Attach the template parameter list to the ConceptDecl
CD->setTemplateParameters(ConceptParams);

// Add the concept declaration to the Translation Unit Decl
Context.getTranslationUnitDecl()->addDecl(CD);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be putting the concepts under the hlsl namespace not under the top level declaration where they may conflict with user-defined declarations.

Suggested change
Context.getTranslationUnitDecl()->addDecl(CD);
NSD->getDeclContext()->addDecl(CD);


return CD;
}

void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
CXXRecordDecl *Decl;
ConceptDecl *TypeBufferConcept =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo

Suggested change
ConceptDecl *TypeBufferConcept =
ConceptDecl *TypedBufferConcept =

constructTypedBufferConceptDecl(*SemaPtr, HLSLNamespace);

Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
.addSimpleTemplateParams(*SemaPtr, {"element_type"})
.addSimpleTemplateParams(*SemaPtr, {"element_type"},
TypeBufferConcept)
.Record;

onCompletion(Decl, [this](CXXRecordDecl *Decl) {
Expand Down
20 changes: 18 additions & 2 deletions clang/test/AST/HLSL/RWBuffer-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@
// instantiated specialization.

// EMPTY: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit RWBuffer
// EMPTY-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type
// EMPTY-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> typename depth 0 index 0 element_type
// EMPTY-NEXT: ConceptSpecializationExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'bool' Concept 0x{{[0-9A-Fa-f]+}} '__is_typed_resource_element_compatible'
// EMPTY-NEXT: ImplicitConceptSpecializationDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc>
// EMPTY-NEXT: TemplateArgument type 'type-parameter-0-0'
// EMPTY-NEXT: TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-0' dependent depth 0 index 0
// EMPTY-NEXT: TemplateTypeParm 0x{{[0-9A-Fa-f]+}} ''
// EMPTY-NEXT: TemplateArgument type 'element_type':'type-parameter-0-0'
// EMPTY-NEXT: TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'element_type' dependent depth 0 index 0
// EMPTY-NEXT: TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'element_type'
// EMPTY-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit <undeserialized declarations> class RWBuffer
// EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final

Expand All @@ -25,7 +33,15 @@ RWBuffer<float> Buffer;
#endif

// CHECK: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit RWBuffer
// CHECK-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type
// CHECK-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> typename depth 0 index 0 element_type
// CHECK-NEXT: ConceptSpecializationExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'bool' Concept 0x{{[0-9A-Fa-f]+}} '__is_typed_resource_element_compatible'
// CHECK-NEXT: ImplicitConceptSpecializationDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc>
// CHECK-NEXT: TemplateArgument type 'type-parameter-0-0'
// CHECK-NEXT: TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'type-parameter-0-0' dependent depth 0 index 0
// CHECK-NEXT: TemplateTypeParm 0x{{[0-9A-Fa-f]+}} ''
// CHECK-NEXT: TemplateArgument type 'element_type':'type-parameter-0-0'
// CHECK-NEXT: TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'element_type' dependent depth 0 index 0
// CHECK-NEXT: TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'element_type'
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class RWBuffer definition

// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
Expand Down
4 changes: 2 additions & 2 deletions clang/test/AST/HLSL/StructuredBuffer-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// instantiated specialization.

// EMPTY: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit StructuredBuffer
// EMPTY-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type
// EMPTY-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> typename depth 0 index 0 element_type
// EMPTY-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit <undeserialized declarations> class StructuredBuffer
// EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final

Expand All @@ -26,7 +26,7 @@ StructuredBuffer<float> Buffer;
#endif

// CHECK: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit StructuredBuffer
// CHECK-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type
// CHECK-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> typename depth 0 index 0 element_type
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class StructuredBuffer definition

// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
Expand Down
15 changes: 13 additions & 2 deletions clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,24 @@ typedef vector<float, 3> float3;
RWBuffer<float3> Buffer;

// expected-error@+2 {{class template 'RWBuffer' requires template arguments}}
// expected-note@*:* {{template declaration from hidden source: template <class element_type> class RWBuffer}}
// expected-note@*:* {{template declaration from hidden source: template <typename element_type> requires __is_typed_resource_element_compatible<element_type> class RWBuffer {}}}
RWBuffer BufferErr1;

// expected-error@+2 {{too few template arguments for class template 'RWBuffer'}}
// expected-note@*:* {{template declaration from hidden source: template <class element_type> class RWBuffer}}
// expected-note@*:* {{template declaration from hidden source: template <typename element_type> requires __is_typed_resource_element_compatible<element_type> class RWBuffer {}}}
RWBuffer<> BufferErr2;

struct threeDoubles {
double a;
double b;
double c;
};

// expected-error@+3 {{constraints not satisfied for class template 'RWBuffer'}}
// expected-note@*:* {{because 'threeDoubles' does not satisfy '__is_typed_resource_element_compatible'}}
// expected-note@*:* {{because 'sizeof(threeDoubles) <= 16UL' (24 <= 16) evaluated to false}}
RWBuffer<threeDoubles> BufferErr3;

[numthreads(1,1,1)]
void main() {
(void)Buffer.h; // expected-error {{'h' is a private member of 'hlsl::RWBuffer<vector<float, 3>>'}}
Expand Down
4 changes: 2 additions & 2 deletions clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ typedef vector<float, 3> float3;
StructuredBuffer<float3> Buffer;

// expected-error@+2 {{class template 'StructuredBuffer' requires template arguments}}
// expected-note@*:* {{template declaration from hidden source: template <class element_type> class StructuredBuffer}}
// expected-note@*:* {{template declaration from hidden source: template <typename element_type> class StructuredBuffer {}}}
StructuredBuffer BufferErr1;

// expected-error@+2 {{too few template arguments for class template 'StructuredBuffer'}}
// expected-note@*:* {{template declaration from hidden source: template <class element_type> class StructuredBuffer}}
// expected-note@*:* {{template declaration from hidden source: template <typename element_type> class StructuredBuffer {}}}
StructuredBuffer<> BufferErr2;

[numthreads(1,1,1)]
Expand Down