[clang] 478c24b - [HLSL] Add implicit resource element type concepts to AST (#112600)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 14 17:01:08 PST 2024
Author: Joshua Batista
Date: 2024-11-14T17:00:58-08:00
New Revision: 478c24b5f86911d14256bad71c85ed0ff061070a
URL: https://github.com/llvm/llvm-project/commit/478c24b5f86911d14256bad71c85ed0ff061070a
DIFF: https://github.com/llvm/llvm-project/commit/478c24b5f86911d14256bad71c85ed0ff061070a.diff
LOG: [HLSL] Add implicit resource element type concepts to AST (#112600)
This PR is step one on the journey to implement resource element type
validation via C++20 concepts. The PR sets up the infrastructure for
injecting implicit concept decls / concept specialization expressions
into the AST, which will then be evaluated after template arguments are
instantiated. This is not meant to be a complete implementation of the
desired validation for HLSL,
there are a couple of missing elements:
1. We need the __builtin_hlsl_is_typed_resource_element_compatible
builtin to be implemented.
2. We need other constraints, like is_intangible
3. We need to put the first 2 points together, and construct a finalized
constraint expression, which should differ between typed and raw buffers
This is just an initial PR that puts some of the core infrastructure in
place.
Added:
clang/test/AST/HLSL/is_typed_resource_element_compatible_concept.hlsl
Modified:
clang/lib/Sema/HLSLExternalSemaSource.cpp
clang/test/AST/HLSL/RWBuffer-AST.hlsl
clang/test/AST/HLSL/StructuredBuffer-AST.hlsl
clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl
Removed:
################################################################################
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index cac15b974a276e..d90a7d3c697a04 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -289,8 +289,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 {
@@ -312,30 +313,129 @@ 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 in
+ constructConceptSpecializationExpr is constructed so that it
+ matches the CSE that is constructed when parsing the below C++ code:
+
+ template<typename T>
+ concept is_typed_resource_element_compatible = sizeof(T) <= 16;
+
+ template<typename element_type> requires
+ is_typed_resource_element_compatible<element_type>
+ struct RWBuffer {
+ element_type Val;
+ };
+
+ 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 TemplateTypeParmDecl is the template for the resource, and is
+ // used to construct a template argumentthat will be used
+ // to construct the ImplicitConceptSpecializationDecl
+ TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
+ Context, // AST context
+ 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);
+
+ QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD);
+
+ // this is the 2nd template argument node, on which
+ // the concept constraint is actually being applied: 'element_type'
+ TemplateArgument ConceptTA = TemplateArgument(ConceptTType);
+
+ QualType CSETType = Context.getTypeDeclType(T);
+
+ // this is the 1st template argument node, which represents
+ // the abstract type that a concept would refer to: 'T'
+ 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);
@@ -355,13 +455,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() {}
@@ -472,10 +572,103 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
.addDefaultHandleConstructor(S);
}
+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 &ElementTypeII = Context.Idents.get("element_type");
+ TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
+ 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(
+ &Context.Idents.get("__is_typed_resource_element_compatible"));
+ Expr *ConstraintExpr = constructTypedBufferConstraintExpr(S, DeclLoc, T);
+
+ // Create a ConceptDecl
+ ConceptDecl *CD =
+ 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
+ NSD->getDeclContext()->addDecl(CD);
+
+ return CD;
+}
+
void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
CXXRecordDecl *Decl;
+ ConceptDecl *TypedBufferConcept =
+ constructTypedBufferConceptDecl(*SemaPtr, HLSLNamespace);
+
Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
- .addSimpleTemplateParams(*SemaPtr, {"element_type"})
+ .addSimpleTemplateParams(*SemaPtr, {"element_type"},
+ TypedBufferConcept)
.Record;
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
diff --git a/clang/test/AST/HLSL/RWBuffer-AST.hlsl b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
index ebddd72ddb1e0e..e3060a2dfa9677 100644
--- a/clang/test/AST/HLSL/RWBuffer-AST.hlsl
+++ b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
@@ -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
@@ -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
diff --git a/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl b/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl
index 521c3d45b20225..081ab1355caaac 100644
--- a/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl
+++ b/clang/test/AST/HLSL/StructuredBuffer-AST.hlsl
@@ -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
@@ -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
diff --git a/clang/test/AST/HLSL/is_typed_resource_element_compatible_concept.hlsl b/clang/test/AST/HLSL/is_typed_resource_element_compatible_concept.hlsl
new file mode 100644
index 00000000000000..414ed6eb821246
--- /dev/null
+++ b/clang/test/AST/HLSL/is_typed_resource_element_compatible_concept.hlsl
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -ast-dump-filter=__is_typed_resource_element_compatible %s | FileCheck %s
+
+// CHECK: ConceptDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> __is_typed_resource_element_compatible
+// CHECK: |-TemplateTypeParmDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> referenced typename depth 0 index 0 element_type
+// CHECK: `-BinaryOperator 0x{{[0-9a-f]+}} <<invalid sloc>> 'bool' lvalue '<='
+// CHECK: |-UnaryExprOrTypeTraitExpr 0x{{[0-9a-f]+}} <<invalid sloc>> 'unsigned long' sizeof 'element_type'
+// CHECK: `-IntegerLiteral 0x{{[0-9a-f]+}} <<invalid sloc>> 'unsigned long' 16
+
+
+RWBuffer<float> Buffer;
diff --git a/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
index 76b5d01b8036eb..a170cef6e5da11 100644
--- a/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
@@ -5,13 +5,24 @@ typedef vector<float, 3> float3;
RWBuffer<float3> Buffer;
// expected-error at +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 at +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 at +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>>'}}
diff --git a/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl
index a472d5519dc51f..552624f13ee5f8 100644
--- a/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/StructuredBuffers.hlsl
@@ -5,11 +5,11 @@ typedef vector<float, 3> float3;
StructuredBuffer<float3> Buffer;
// expected-error at +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 at +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)]
More information about the cfe-commits
mailing list