@@ -289,8 +289,9 @@ struct BuiltinTypeDeclBuilder {
289289 }
290290
291291 TemplateParameterListBuilder addTemplateArgumentList (Sema &S);
292- BuiltinTypeDeclBuilder &addSimpleTemplateParams (Sema &S,
293- ArrayRef<StringRef> Names);
292+ BuiltinTypeDeclBuilder &
293+ addSimpleTemplateParams (Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD);
294+ BuiltinTypeDeclBuilder &addConceptSpecializationExpr (Sema &S);
294295};
295296
296297struct TemplateParameterListBuilder {
@@ -312,8 +313,9 @@ struct TemplateParameterListBuilder {
312313 S.Context , Builder.Record ->getDeclContext (), SourceLocation (),
313314 SourceLocation (), /* TemplateDepth */ 0 , Position,
314315 &S.Context .Idents .get (Name, tok::TokenKind::identifier),
315- /* Typename */ false ,
316- /* ParameterPack */ false );
316+ /* Typename */ true ,
317+ /* ParameterPack */ false ,
318+ /* HasTypeConstraint*/ false );
317319 if (!DefaultValue.isNull ())
318320 Decl->setDefaultArgument (
319321 S.Context , S.getTrivialTemplateArgumentLoc (DefaultValue, QualType (),
@@ -323,19 +325,117 @@ struct TemplateParameterListBuilder {
323325 return *this ;
324326 }
325327
326- BuiltinTypeDeclBuilder &finalizeTemplateArgs () {
328+ // The concept specialization expression (CSE) constructed in
329+ // constructConceptSpecializationExpr is constructed so that it
330+ // matches the CSE that is constructed when parsing the below C++ code:
331+ //
332+ // template<typename T>
333+ // concept is_typed_resource_element_compatible =
334+ // __builtin_hlsl_typed_resource_element_compatible<T>
335+ //
336+ // template<typename element_type> requires
337+ // is_typed_resource_element_compatible<element_type>
338+ // struct RWBuffer {
339+ // element_type Val;
340+ // };
341+ //
342+ // int fn() {
343+ // RWBuffer<int> Buf;
344+ // }
345+ //
346+ // When dumping the AST and filtering for "RWBuffer", the resulting AST
347+ // structure is what we're trying to construct below, specifically the
348+ // CSE portion.
349+ ConceptSpecializationExpr *
350+ constructConceptSpecializationExpr (Sema &S, ConceptDecl *CD) {
351+ ASTContext &Context = S.getASTContext ();
352+ SourceLocation Loc = Builder.Record ->getBeginLoc ();
353+ DeclarationNameInfo DNI (CD->getDeclName (), Loc);
354+ NestedNameSpecifierLoc NNSLoc;
355+ DeclContext *DC = Builder.Record ->getDeclContext ();
356+ TemplateArgumentListInfo TALI (Loc, Loc);
357+
358+ // Assume that the concept decl has just one template parameter
359+ // This parameter should have been added when CD was constructed
360+ // in getTypedBufferConceptDecl
361+ assert (CD->getTemplateParameters ()->size () == 1 &&
362+ " unexpected concept decl parameter count" );
363+ TemplateTypeParmDecl *ConceptTTPD = dyn_cast<TemplateTypeParmDecl>(
364+ CD->getTemplateParameters ()->getParam (0 ));
365+
366+ // this TemplateTypeParmDecl is the template for the resource, and is
367+ // used to construct a template argumentthat will be used
368+ // to construct the ImplicitConceptSpecializationDecl
369+ TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create (
370+ Context, // AST context
371+ Builder.Record ->getDeclContext (), // DeclContext
372+ SourceLocation (), SourceLocation (),
373+ /* depth=*/ 0 , // Depth in the template parameter list
374+ /* position=*/ 0 , // Position in the template parameter list
375+ /* id=*/ nullptr , // Identifier for 'T'
376+ /* Typename=*/ true , // Indicates this is a 'typename' or 'class'
377+ /* ParameterPack=*/ false , // Not a parameter pack
378+ /* HasTypeConstraint=*/ false // Has no type constraint
379+ );
380+
381+ T->setDeclContext (DC);
382+
383+ QualType ConceptTType = Context.getTypeDeclType (ConceptTTPD);
384+
385+ // this is the 2nd template argument node, on which
386+ // the concept constraint is actually being applied: 'element_type'
387+ TemplateArgument ConceptTA = TemplateArgument (ConceptTType);
388+
389+ QualType CSETType = Context.getTypeDeclType (T);
390+
391+ // this is the 1st template argument node, which represents
392+ // the abstract type that a concept would refer to: 'T'
393+ TemplateArgument CSETA = TemplateArgument (CSETType);
394+
395+ ImplicitConceptSpecializationDecl *ImplicitCSEDecl =
396+ ImplicitConceptSpecializationDecl::Create (
397+ Context, Builder.Record ->getDeclContext (), Loc, {CSETA});
398+
399+ // Constraint satisfaction is used to construct the
400+ // ConceptSpecailizationExpr, and represents the 2nd Template Argument,
401+ // located at the bottom of the sample AST above.
402+ const ConstraintSatisfaction CS (CD, {ConceptTA});
403+ TemplateArgumentLoc TAL = S.getTrivialTemplateArgumentLoc (
404+ ConceptTA, QualType (), SourceLocation ());
405+
406+ TALI.addArgument (TAL);
407+ const ASTTemplateArgumentListInfo *ATALI =
408+ ASTTemplateArgumentListInfo::Create (Context, TALI);
409+
410+ // In the concept reference, ATALI is what adds the extra
411+ // TemplateArgument node underneath CSE
412+ ConceptReference *CR =
413+ ConceptReference::Create (Context, NNSLoc, Loc, DNI, CD, CD, ATALI);
414+
415+ ConceptSpecializationExpr *CSE =
416+ ConceptSpecializationExpr::Create (Context, CR, ImplicitCSEDecl, &CS);
417+
418+ return CSE;
419+ }
420+
421+ BuiltinTypeDeclBuilder &finalizeTemplateArgs (ConceptDecl *CD = nullptr ) {
327422 if (Params.empty ())
328423 return Builder;
424+ ConceptSpecializationExpr *CSE =
425+ CD ? constructConceptSpecializationExpr (S, CD) : nullptr ;
426+
329427 auto *ParamList = TemplateParameterList::Create (S.Context , SourceLocation (),
330428 SourceLocation (), Params,
331- SourceLocation (), nullptr );
429+ SourceLocation (), CSE );
332430 Builder.Template = ClassTemplateDecl::Create (
333431 S.Context , Builder.Record ->getDeclContext (), SourceLocation (),
334432 DeclarationName (Builder.Record ->getIdentifier ()), ParamList,
335433 Builder.Record );
434+
336435 Builder.Record ->setDescribedClassTemplate (Builder.Template );
337436 Builder.Template ->setImplicit (true );
338437 Builder.Template ->setLexicalDeclContext (Builder.Record ->getDeclContext ());
438+
339439 // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
340440 // make visible.
341441 Builder.Template ->setPreviousDecl (Builder.PrevTemplate );
@@ -355,13 +455,12 @@ BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) {
355455 return TemplateParameterListBuilder (S, *this );
356456}
357457
358- BuiltinTypeDeclBuilder &
359- BuiltinTypeDeclBuilder::addSimpleTemplateParams (Sema &S,
360- ArrayRef<StringRef> Names) {
458+ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addSimpleTemplateParams (
459+ Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD = nullptr ) {
361460 TemplateParameterListBuilder Builder = this ->addTemplateArgumentList (S);
362461 for (StringRef Name : Names)
363462 Builder.addTypeParameter (Name);
364- return Builder.finalizeTemplateArgs ();
463+ return Builder.finalizeTemplateArgs (CD );
365464}
366465
367466HLSLExternalSemaSource::~HLSLExternalSemaSource () {}
@@ -472,10 +571,73 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
472571 .addDefaultHandleConstructor (S);
473572}
474573
574+ Expr *constructTypedBufferConstraintExpr (Sema &S, SourceLocation NameLoc,
575+ TemplateTypeParmDecl *T) {
576+ ASTContext &Context = S.getASTContext ();
577+
578+ // Obtain the QualType for 'unsigned long'
579+ QualType BoolTy = Context.BoolTy ;
580+
581+ // Create a QualType that points to this TemplateTypeParmDecl
582+ QualType TType = Context.getTypeDeclType (T);
583+
584+ // Create a TypeSourceInfo for the template type parameter 'T'
585+ TypeSourceInfo *TTypeSourceInfo =
586+ Context.getTrivialTypeSourceInfo (TType, NameLoc);
587+
588+ TypeTraitExpr *TypedResExpr = TypeTraitExpr::Create (
589+ Context, BoolTy, NameLoc, UTT_IsTypedResourceElementCompatible,
590+ {TTypeSourceInfo}, NameLoc, true );
591+
592+ return TypedResExpr;
593+ }
594+
595+ ConceptDecl *constructTypedBufferConceptDecl (Sema &S, NamespaceDecl *NSD) {
596+ ASTContext &Context = S.getASTContext ();
597+ DeclContext *DC = NSD->getDeclContext ();
598+ SourceLocation DeclLoc = SourceLocation ();
599+
600+ IdentifierInfo &ElementTypeII = Context.Idents .get (" element_type" );
601+ TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create (
602+ Context, NSD->getDeclContext (), DeclLoc, DeclLoc,
603+ /* depth=*/ 0 ,
604+ /* position=*/ 0 ,
605+ /* id=*/ &ElementTypeII,
606+ /* Typename=*/ true ,
607+ /* ParameterPack=*/ false );
608+
609+ T->setDeclContext (DC);
610+ T->setReferenced ();
611+
612+ // Create and Attach Template Parameter List to ConceptDecl
613+ TemplateParameterList *ConceptParams = TemplateParameterList::Create (
614+ Context, DeclLoc, DeclLoc, {T}, DeclLoc, nullptr );
615+
616+ DeclarationName DeclName = DeclarationName (
617+ &Context.Idents .get (" __is_typed_resource_element_compatible" ));
618+ Expr *ConstraintExpr = constructTypedBufferConstraintExpr (S, DeclLoc, T);
619+
620+ // Create a ConceptDecl
621+ ConceptDecl *CD =
622+ ConceptDecl::Create (Context, NSD->getDeclContext (), DeclLoc, DeclName,
623+ ConceptParams, ConstraintExpr);
624+
625+ // Attach the template parameter list to the ConceptDecl
626+ CD->setTemplateParameters (ConceptParams);
627+
628+ // Add the concept declaration to the Translation Unit Decl
629+ NSD->getDeclContext ()->addDecl (CD);
630+
631+ return CD;
632+ }
633+
475634void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations () {
476635 CXXRecordDecl *Decl;
636+ ConceptDecl *TypedBufferConcept =
637+ constructTypedBufferConceptDecl (*SemaPtr, HLSLNamespace);
477638 Decl = BuiltinTypeDeclBuilder (*SemaPtr, HLSLNamespace, " RWBuffer" )
478- .addSimpleTemplateParams (*SemaPtr, {" element_type" })
639+ .addSimpleTemplateParams (*SemaPtr, {" element_type" },
640+ TypedBufferConcept)
479641 .Record ;
480642
481643 onCompletion (Decl, [this ](CXXRecordDecl *Decl) {
0 commit comments