@@ -289,8 +289,9 @@ struct BuiltinTypeDeclBuilder {
289
289
}
290
290
291
291
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);
294
295
};
295
296
296
297
struct TemplateParameterListBuilder {
@@ -312,8 +313,9 @@ struct TemplateParameterListBuilder {
312
313
S.Context , Builder.Record ->getDeclContext (), SourceLocation (),
313
314
SourceLocation (), /* TemplateDepth */ 0 , Position,
314
315
&S.Context .Idents .get (Name, tok::TokenKind::identifier),
315
- /* Typename */ false ,
316
- /* ParameterPack */ false );
316
+ /* Typename */ true ,
317
+ /* ParameterPack */ false ,
318
+ /* HasTypeConstraint*/ false );
317
319
if (!DefaultValue.isNull ())
318
320
Decl->setDefaultArgument (
319
321
S.Context , S.getTrivialTemplateArgumentLoc (DefaultValue, QualType (),
@@ -323,19 +325,117 @@ struct TemplateParameterListBuilder {
323
325
return *this ;
324
326
}
325
327
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 ) {
327
422
if (Params.empty ())
328
423
return Builder;
424
+ ConceptSpecializationExpr *CSE =
425
+ CD ? constructConceptSpecializationExpr (S, CD) : nullptr ;
426
+
329
427
auto *ParamList = TemplateParameterList::Create (S.Context , SourceLocation (),
330
428
SourceLocation (), Params,
331
- SourceLocation (), nullptr );
429
+ SourceLocation (), CSE );
332
430
Builder.Template = ClassTemplateDecl::Create (
333
431
S.Context , Builder.Record ->getDeclContext (), SourceLocation (),
334
432
DeclarationName (Builder.Record ->getIdentifier ()), ParamList,
335
433
Builder.Record );
434
+
336
435
Builder.Record ->setDescribedClassTemplate (Builder.Template );
337
436
Builder.Template ->setImplicit (true );
338
437
Builder.Template ->setLexicalDeclContext (Builder.Record ->getDeclContext ());
438
+
339
439
// NOTE: setPreviousDecl before addDecl so new decl replace old decl when
340
440
// make visible.
341
441
Builder.Template ->setPreviousDecl (Builder.PrevTemplate );
@@ -355,13 +455,12 @@ BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) {
355
455
return TemplateParameterListBuilder (S, *this );
356
456
}
357
457
358
- BuiltinTypeDeclBuilder &
359
- BuiltinTypeDeclBuilder::addSimpleTemplateParams (Sema &S,
360
- ArrayRef<StringRef> Names) {
458
+ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addSimpleTemplateParams (
459
+ Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD = nullptr ) {
361
460
TemplateParameterListBuilder Builder = this ->addTemplateArgumentList (S);
362
461
for (StringRef Name : Names)
363
462
Builder.addTypeParameter (Name);
364
- return Builder.finalizeTemplateArgs ();
463
+ return Builder.finalizeTemplateArgs (CD );
365
464
}
366
465
367
466
HLSLExternalSemaSource::~HLSLExternalSemaSource () {}
@@ -472,10 +571,73 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
472
571
.addDefaultHandleConstructor (S);
473
572
}
474
573
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
+
475
634
void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations () {
476
635
CXXRecordDecl *Decl;
636
+ ConceptDecl *TypedBufferConcept =
637
+ constructTypedBufferConceptDecl (*SemaPtr, HLSLNamespace);
477
638
Decl = BuiltinTypeDeclBuilder (*SemaPtr, HLSLNamespace, " RWBuffer" )
478
- .addSimpleTemplateParams (*SemaPtr, {" element_type" })
639
+ .addSimpleTemplateParams (*SemaPtr, {" element_type" },
640
+ TypedBufferConcept)
479
641
.Record ;
480
642
481
643
onCompletion (Decl, [this ](CXXRecordDecl *Decl) {
0 commit comments