@@ -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,30 +313,129 @@ 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 (),
320
322
SourceLocation ()));
321
-
322
323
Params.emplace_back (Decl);
323
324
return *this ;
324
325
}
325
326
326
- BuiltinTypeDeclBuilder &finalizeTemplateArgs () {
327
+ /*
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 = sizeof(T) <= 16;
334
+
335
+ template<typename element_type> requires
336
+ is_typed_resource_element_compatible<element_type>
337
+ struct RWBuffer {
338
+ element_type Val;
339
+ };
340
+
341
+ int fn() {
342
+ RWBuffer<int> Buf;
343
+ }
344
+
345
+ When dumping the AST and filtering for "RWBuffer", the resulting AST
346
+ structure is what we're trying to construct below, specifically the
347
+ CSE portion.
348
+ */
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,13 @@ 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
+
464
+ return Builder.finalizeTemplateArgs (CD);
365
465
}
366
466
367
467
HLSLExternalSemaSource::~HLSLExternalSemaSource () {}
@@ -472,10 +572,103 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
472
572
.addDefaultHandleConstructor (S);
473
573
}
474
574
575
+ BinaryOperator *constructSizeOfLEQ16Expr (ASTContext &Context,
576
+ SourceLocation NameLoc,
577
+ TemplateTypeParmDecl *T) {
578
+ // Obtain the QualType for 'unsigned long'
579
+ QualType UnsignedLongType = Context.UnsignedLongTy ;
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
+ UnaryExprOrTypeTraitExpr *sizeOfExpr = new (Context) UnaryExprOrTypeTraitExpr (
589
+ UETT_SizeOf, TTypeSourceInfo, UnsignedLongType, NameLoc, NameLoc);
590
+
591
+ // Create an IntegerLiteral for the value '16' with size type
592
+ QualType SizeType = Context.getSizeType ();
593
+ llvm::APInt SizeValue = llvm::APInt (Context.getTypeSize (SizeType), 16 );
594
+ IntegerLiteral *SizeLiteral =
595
+ new (Context) IntegerLiteral (Context, SizeValue, SizeType, NameLoc);
596
+
597
+ QualType BoolTy = Context.BoolTy ;
598
+
599
+ BinaryOperator *binaryOperator =
600
+ BinaryOperator::Create (Context, sizeOfExpr, // Left-hand side expression
601
+ SizeLiteral, // Right-hand side expression
602
+ BO_LE, // Binary operator kind (<=)
603
+ BoolTy, // Result type (bool)
604
+ VK_LValue, // Value kind
605
+ OK_Ordinary, // Object kind
606
+ NameLoc, // Source location of operator
607
+ FPOptionsOverride ());
608
+
609
+ return binaryOperator;
610
+ }
611
+
612
+ Expr *constructTypedBufferConstraintExpr (Sema &S, SourceLocation NameLoc,
613
+ TemplateTypeParmDecl *T) {
614
+ ASTContext &Context = S.getASTContext ();
615
+
616
+ // first get the "sizeof(T) <= 16" expression, as a binary operator
617
+ BinaryOperator *SizeOfLEQ16 = constructSizeOfLEQ16Expr (Context, NameLoc, T);
618
+ // TODO: add the 'builtin_hlsl_is_typed_resource_element_compatible' builtin
619
+ // and return a binary operator that evaluates the builtin on the given
620
+ // template type parameter 'T'.
621
+ // Defined in issue https://github.com/llvm/llvm-project/issues/113223
622
+ return SizeOfLEQ16;
623
+ }
624
+
625
+ ConceptDecl *constructTypedBufferConceptDecl (Sema &S, NamespaceDecl *NSD) {
626
+ ASTContext &Context = S.getASTContext ();
627
+ DeclContext *DC = NSD->getDeclContext ();
628
+ SourceLocation DeclLoc = SourceLocation ();
629
+
630
+ IdentifierInfo &ElementTypeII = Context.Idents .get (" element_type" );
631
+ TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create (
632
+ Context, NSD->getDeclContext (), DeclLoc, DeclLoc,
633
+ /* depth=*/ 0 ,
634
+ /* position=*/ 0 ,
635
+ /* id=*/ &ElementTypeII,
636
+ /* Typename=*/ true ,
637
+ /* ParameterPack=*/ false );
638
+
639
+ T->setDeclContext (DC);
640
+ T->setReferenced ();
641
+
642
+ // Create and Attach Template Parameter List to ConceptDecl
643
+ TemplateParameterList *ConceptParams = TemplateParameterList::Create (
644
+ Context, DeclLoc, DeclLoc, {T}, DeclLoc, nullptr );
645
+
646
+ DeclarationName DeclName = DeclarationName (
647
+ &Context.Idents .get (" __is_typed_resource_element_compatible" ));
648
+ Expr *ConstraintExpr = constructTypedBufferConstraintExpr (S, DeclLoc, T);
649
+
650
+ // Create a ConceptDecl
651
+ ConceptDecl *CD =
652
+ ConceptDecl::Create (Context, NSD->getDeclContext (), DeclLoc, DeclName,
653
+ ConceptParams, ConstraintExpr);
654
+
655
+ // Attach the template parameter list to the ConceptDecl
656
+ CD->setTemplateParameters (ConceptParams);
657
+
658
+ // Add the concept declaration to the Translation Unit Decl
659
+ NSD->getDeclContext ()->addDecl (CD);
660
+
661
+ return CD;
662
+ }
663
+
475
664
void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations () {
476
665
CXXRecordDecl *Decl;
666
+ ConceptDecl *TypedBufferConcept =
667
+ constructTypedBufferConceptDecl (*SemaPtr, HLSLNamespace);
668
+
477
669
Decl = BuiltinTypeDeclBuilder (*SemaPtr, HLSLNamespace, " RWBuffer" )
478
- .addSimpleTemplateParams (*SemaPtr, {" element_type" })
670
+ .addSimpleTemplateParams (*SemaPtr, {" element_type" },
671
+ TypedBufferConcept)
479
672
.Record ;
480
673
481
674
onCompletion (Decl, [this ](CXXRecordDecl *Decl) {
0 commit comments