[clang] [HLSL] Add implicit resource element type concepts to AST (PR #112600)
Joshua Batista via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 18 14:06:00 PDT 2024
https://github.com/bob80905 updated https://github.com/llvm/llvm-project/pull/112600
>From 0739f6da81d7c1edd9578ae4ff9dd699e5c828c6 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 10 Oct 2024 14:31:25 -0700
Subject: [PATCH 01/16] ConceptSpecializationExpr shows up in AST!!!
---
.../clang/Sema/HLSLExternalSemaSource.h | 2 +
clang/lib/AST/DeclTemplate.cpp | 6 +-
clang/lib/Sema/HLSLExternalSemaSource.cpp | 154 +++++++++++++++++-
3 files changed, 158 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/Sema/HLSLExternalSemaSource.h b/clang/include/clang/Sema/HLSLExternalSemaSource.h
index 3c7495e66055dc..0266bc0f8b336e 100644
--- a/clang/include/clang/Sema/HLSLExternalSemaSource.h
+++ b/clang/include/clang/Sema/HLSLExternalSemaSource.h
@@ -47,6 +47,8 @@ class HLSLExternalSemaSource : public ExternalSemaSource {
using ExternalASTSource::CompleteType;
/// Complete an incomplete HLSL builtin type
void CompleteType(TagDecl *Tag) override;
+
+ ConceptDecl *getTypedBufferConceptDecl(Sema &S, CXXRecordDecl *Decl);
};
} // namespace clang
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 6fe817c5ef1c6b..2eae6d14718b86 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -1080,10 +1080,10 @@ ConceptDecl *ConceptDecl::Create(ASTContext &C, DeclContext *DC,
TemplateParameterList *Params,
Expr *ConstraintExpr) {
bool Invalid = AdoptTemplateParameterList(Params, DC);
- auto *TD = new (C, DC) ConceptDecl(DC, L, Name, Params, ConstraintExpr);
+ auto *CD = new (C, DC) ConceptDecl(DC, L, Name, Params, ConstraintExpr);
if (Invalid)
- TD->setInvalidDecl();
- return TD;
+ CD->setInvalidDecl();
+ return CD;
}
ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 2913d16fca4823..8104513857027c 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -304,6 +304,7 @@ struct BuiltinTypeDeclBuilder {
TemplateParameterListBuilder addTemplateArgumentList(Sema &S);
BuiltinTypeDeclBuilder &addSimpleTemplateParams(Sema &S,
ArrayRef<StringRef> Names);
+ BuiltinTypeDeclBuilder &addConceptSpecializationExpr(Sema &S);
};
struct TemplateParameterListBuilder {
@@ -326,7 +327,8 @@ struct TemplateParameterListBuilder {
SourceLocation(), /* TemplateDepth */ 0, Position,
&S.Context.Idents.get(Name, tok::TokenKind::identifier),
/* Typename */ false,
- /* ParameterPack */ false);
+ /* ParameterPack */ false,
+ /* HasTypeConstraint*/ true);
if (!DefaultValue.isNull())
Decl->setDefaultArgument(
S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(),
@@ -336,6 +338,152 @@ struct TemplateParameterListBuilder {
return *this;
}
+ Expr *getTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
+ TemplateTypeParmDecl *T) {
+ clang::ASTContext &context = S.getASTContext();
+ // Obtain the QualType for 'unsigned long'
+ clang::QualType unsignedLongType = context.UnsignedLongTy;
+
+ // Create a QualType that points to this TemplateTypeParmDecl
+ clang::QualType TType = context.getTypeDeclType(T);
+
+ // Create a TypeSourceInfo for the template type parameter 'T'
+ clang::TypeSourceInfo *TTypeSourceInfo =
+ context.getTrivialTypeSourceInfo(TType, NameLoc);
+
+ clang::UnaryExprOrTypeTraitExpr *sizeofExpr = new (S.getASTContext())
+ clang::UnaryExprOrTypeTraitExpr(clang::UETT_SizeOf, TTypeSourceInfo,
+ unsignedLongType, NameLoc, NameLoc);
+
+ // Create an IntegerLiteral for the value '16'
+ llvm::APInt intValue(context.getIntWidth(context.IntTy), 4);
+ clang::IntegerLiteral *intLiteral = new (context)
+ clang::IntegerLiteral(context, intValue, context.IntTy, NameLoc);
+
+ // Create an ImplicitCastExpr to cast 'int' to 'unsigned long'
+ FPOptionsOverride fpoo = FPOptionsOverride();
+ clang::ImplicitCastExpr *implicitCastExpr = clang::ImplicitCastExpr::Create(
+ context,
+ unsignedLongType, // The type we are casting to (QualType for 'unsigned
+ // long')
+ clang::CK_IntegralCast, // CastKind (e.g., Integral cast)
+ intLiteral, // Sub-expression being cast
+ nullptr, // Base path, usually null for implicit casts
+ clang::VK_XValue,
+ fpoo // Value kind, typically VK_RValue for implicit casts
+ );
+
+ clang::QualType BoolTy = context.BoolTy;
+
+ clang::BinaryOperator *binaryOperator = clang::BinaryOperator::Create(
+ context, sizeofExpr, // Left-hand side expression
+ implicitCastExpr, // Right-hand side expression
+ clang::BO_LE, // Binary operator kind (<=)
+ BoolTy, // Result type (bool)
+ clang::VK_XValue, // Value kind
+ clang::OK_Ordinary, // Object kind
+ NameLoc, // Source location of operator
+ fpoo);
+
+ return binaryOperator;
+ }
+
+ ConceptDecl *getTypedBufferConceptDecl(Sema &S, CXXRecordDecl *Decl) {
+ DeclContext *DC = S.CurContext;
+ clang::ASTContext &context = S.getASTContext();
+ SourceLocation NameLoc = Decl->getBeginLoc();
+ IdentifierInfo *Name = Decl->getIdentifier();
+
+ clang::TemplateTypeParmDecl *T = clang::TemplateTypeParmDecl::Create(
+ context, // AST context
+ context.getTranslationUnitDecl(), // DeclContext
+ NameLoc, // SourceLocation of 'T'
+ NameLoc, // SourceLocation of 'T' again
+ /*depth=*/0, // Depth in the template parameter list
+ /*position=*/0, // Position in the template parameter list
+ /*id=*/Name, // Identifier for 'T'
+ /*Typename=*/true, // Indicates this is a 'typename' or 'class'
+ /*ParameterPack=*/false // Not a parameter pack
+ );
+
+ T->setDeclContext(DC);
+ T->setReferenced();
+
+ // Create and Attach Template Parameter List to ConceptDecl
+
+ llvm::ArrayRef<NamedDecl *> TemplateParamArrayRef = {T};
+ clang::TemplateParameterList *Params = clang::TemplateParameterList::Create(
+ context,
+ NameLoc, // Source location of the template parameter list start
+ NameLoc, // Source location of the template parameter list end
+ TemplateParamArrayRef, // Template parameter (list as an ArrayRef)
+ NameLoc, // Source location of the template parameter list within
+ // concept
+ nullptr // Source location of the template parameter list end within
+ // concept
+ );
+
+ Expr *ConstraintExpr = getTypedBufferConstraintExpr(S, NameLoc, T);
+
+ DeclarationName DeclName = DeclarationName(Name);
+ // Create a ConceptDecl
+ clang::ConceptDecl *conceptDecl = clang::ConceptDecl::Create(
+ context,
+ context.getTranslationUnitDecl(), // DeclContext
+ NameLoc, // Source location of start of concept
+ DeclName, // Source location of end of concept
+ Params, // Template type parameter
+ ConstraintExpr // Expression defining the concept
+ );
+
+ // Attach the template parameter list to the ConceptDecl
+ conceptDecl->setTemplateParameters(Params);
+
+ // Add the concept declaration to the Translation Unit Decl
+ context.getTranslationUnitDecl()->addDecl(conceptDecl);
+
+ return conceptDecl;
+ }
+
+ BuiltinTypeDeclBuilder &addConceptSpecializationExpr(Sema &S) {
+ ASTContext &context = S.getASTContext();
+ SourceLocation loc = Builder.Record->getBeginLoc();
+ ConceptDecl *CD = getTypedBufferConceptDecl(S, Builder.Record);
+ DeclarationNameInfo DNI(Builder.Record->getDeclName(), loc);
+ NestedNameSpecifierLoc NNS;
+ ClassTemplateDecl *TD = Builder.Template;
+
+ TemplateArgumentListInfo TALI(loc, loc);
+ const ASTTemplateArgumentListInfo *ATALI =
+ ASTTemplateArgumentListInfo::Create(context, TALI);
+
+ ConceptReference *CR = ConceptReference::Create(
+ S.getASTContext(), NNS, loc, DNI, Builder.Record, CD, ATALI);
+
+ TemplateTypeParmDecl *T = dyn_cast<TemplateTypeParmDecl>(
+ TD->getTemplateParameters()->getParam(0));
+
+ clang::QualType TType = context.getTypeDeclType(T);
+
+ ArrayRef<TemplateArgument> ConvertedArgs = {TemplateArgument(TType)};
+
+ ImplicitConceptSpecializationDecl *IDecl =
+ ImplicitConceptSpecializationDecl::Create(
+ context, Builder.Record->getDeclContext(), loc, ConvertedArgs);
+ const ConstraintSatisfaction CS(CD, ConvertedArgs);
+
+ TemplateParameterList *templateParams = TD->getTemplateParameters();
+ ConceptSpecializationExpr *CSE =
+ ConceptSpecializationExpr::Create(context, CR, IDecl, &CS);
+
+ TD->setTemplateParameters(templateParams);
+ T->setTypeConstraint(CR, CSE);
+
+ Builder.Record->getDeclContext()->addDecl(IDecl);
+
+ return Builder;
+ }
+
BuiltinTypeDeclBuilder &finalizeTemplateArgs() {
if (Params.empty())
return Builder;
@@ -346,9 +494,12 @@ struct TemplateParameterListBuilder {
S.Context, Builder.Record->getDeclContext(), SourceLocation(),
DeclarationName(Builder.Record->getIdentifier()), ParamList,
Builder.Record);
+ addConceptSpecializationExpr(S);
+
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);
@@ -374,6 +525,7 @@ BuiltinTypeDeclBuilder::addSimpleTemplateParams(Sema &S,
TemplateParameterListBuilder Builder = this->addTemplateArgumentList(S);
for (StringRef Name : Names)
Builder.addTypeParameter(Name);
+
return Builder.finalizeTemplateArgs();
}
>From d1cb98e4cd2a9ffed967cb673760d44799fb20dd Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 10 Oct 2024 15:51:23 -0700
Subject: [PATCH 02/16] CSE is in the right spot in the AST
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 37 ++++++++++++++---------
1 file changed, 23 insertions(+), 14 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 8104513857027c..885ed312d8ed51 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -445,14 +445,13 @@ struct TemplateParameterListBuilder {
return conceptDecl;
}
- BuiltinTypeDeclBuilder &addConceptSpecializationExpr(Sema &S) {
+ ConceptSpecializationExpr *getConceptSpecializationExpr(Sema &S) {
ASTContext &context = S.getASTContext();
SourceLocation loc = Builder.Record->getBeginLoc();
ConceptDecl *CD = getTypedBufferConceptDecl(S, Builder.Record);
DeclarationNameInfo DNI(Builder.Record->getDeclName(), loc);
NestedNameSpecifierLoc NNS;
- ClassTemplateDecl *TD = Builder.Template;
-
+ DeclContext *DC = Builder.Record->getDeclContext();
TemplateArgumentListInfo TALI(loc, loc);
const ASTTemplateArgumentListInfo *ATALI =
ASTTemplateArgumentListInfo::Create(context, TALI);
@@ -460,8 +459,22 @@ struct TemplateParameterListBuilder {
ConceptReference *CR = ConceptReference::Create(
S.getASTContext(), NNS, loc, DNI, Builder.Record, CD, ATALI);
- TemplateTypeParmDecl *T = dyn_cast<TemplateTypeParmDecl>(
- TD->getTemplateParameters()->getParam(0));
+ clang::TemplateTypeParmDecl *T =
+ clang::TemplateTypeParmDecl::Create(
+ context, // AST context
+ context.getTranslationUnitDecl(), // DeclContext
+ loc, // SourceLocation of 'T'
+ loc, // SourceLocation of 'T' again
+ /*depth=*/0, // Depth in the template parameter list
+ /*position=*/0, // Position in the template parameter list
+ /*id=*/Builder.Record->getIdentifier(), // Identifier for 'T'
+ /*Typename=*/true, // Indicates this is a 'typename' or 'class'
+ /*ParameterPack=*/false,// Not a parameter pack
+ /*HasTypeConstraint=*/true // Not a parameter pack
+ );
+
+ T->setDeclContext(DC);
+ T->setReferenced();
clang::QualType TType = context.getTypeDeclType(T);
@@ -472,29 +485,25 @@ struct TemplateParameterListBuilder {
context, Builder.Record->getDeclContext(), loc, ConvertedArgs);
const ConstraintSatisfaction CS(CD, ConvertedArgs);
- TemplateParameterList *templateParams = TD->getTemplateParameters();
ConceptSpecializationExpr *CSE =
ConceptSpecializationExpr::Create(context, CR, IDecl, &CS);
-
- TD->setTemplateParameters(templateParams);
T->setTypeConstraint(CR, CSE);
-
- Builder.Record->getDeclContext()->addDecl(IDecl);
-
- return Builder;
+
+ return CSE;
}
BuiltinTypeDeclBuilder &finalizeTemplateArgs() {
if (Params.empty())
return Builder;
+ ConceptSpecializationExpr *CSE = getConceptSpecializationExpr(S);
+
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);
- addConceptSpecializationExpr(S);
Builder.Record->setDescribedClassTemplate(Builder.Template);
Builder.Template->setImplicit(true);
>From ff195ae2a67a3354f64e037e0af2cf8d48b87d32 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 10 Oct 2024 17:55:46 -0700
Subject: [PATCH 03/16] templateArg is aligned correctly on the AST
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 885ed312d8ed51..eed793256399ff 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -449,15 +449,15 @@ struct TemplateParameterListBuilder {
ASTContext &context = S.getASTContext();
SourceLocation loc = Builder.Record->getBeginLoc();
ConceptDecl *CD = getTypedBufferConceptDecl(S, Builder.Record);
- DeclarationNameInfo DNI(Builder.Record->getDeclName(), loc);
+ DeclarationNameInfo DNI(CD->getDeclName(), loc);
NestedNameSpecifierLoc NNS;
DeclContext *DC = Builder.Record->getDeclContext();
TemplateArgumentListInfo TALI(loc, loc);
const ASTTemplateArgumentListInfo *ATALI =
ASTTemplateArgumentListInfo::Create(context, TALI);
- ConceptReference *CR = ConceptReference::Create(
- S.getASTContext(), NNS, loc, DNI, Builder.Record, CD, ATALI);
+ ConceptReference *CR = ConceptReference::Create(S.getASTContext(), NNS, loc,
+ DNI, CD, CD, ATALI);
clang::TemplateTypeParmDecl *T =
clang::TemplateTypeParmDecl::Create(
@@ -478,17 +478,18 @@ struct TemplateParameterListBuilder {
clang::QualType TType = context.getTypeDeclType(T);
- ArrayRef<TemplateArgument> ConvertedArgs = {TemplateArgument(TType)};
+ ArrayRef<TemplateArgument> ConvertedArgs = {TemplateArgument(TType),
+ TemplateArgument(TType)};
ImplicitConceptSpecializationDecl *IDecl =
ImplicitConceptSpecializationDecl::Create(
context, Builder.Record->getDeclContext(), loc, ConvertedArgs);
+
const ConstraintSatisfaction CS(CD, ConvertedArgs);
ConceptSpecializationExpr *CSE =
ConceptSpecializationExpr::Create(context, CR, IDecl, &CS);
T->setTypeConstraint(CR, CSE);
-
return CSE;
}
>From 73f932f4179575660135bfb02166e1251a917fa7 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Tue, 15 Oct 2024 11:42:26 -0700
Subject: [PATCH 04/16] template arguments are in the right spot!
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 106 ++++++++++++++--------
1 file changed, 67 insertions(+), 39 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index eed793256399ff..0135ff096b946d 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -338,6 +338,27 @@ struct TemplateParameterListBuilder {
return *this;
}
+ TemplateParameterListBuilder &
+ addTypenameTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
+ if (Builder.Record->isCompleteDefinition())
+ return *this;
+ unsigned Position = static_cast<unsigned>(Params.size());
+ auto *Decl = TemplateTypeParmDecl::Create(
+ S.Context, Builder.Record->getDeclContext(), SourceLocation(),
+ SourceLocation(), /* TemplateDepth */ 0, Position,
+ &S.Context.Idents.get(Name, tok::TokenKind::identifier),
+ /* Typename */ true,
+ /* ParameterPack */ false,
+ /* HasTypeConstraint*/ false);
+ if (!DefaultValue.isNull())
+ Decl->setDefaultArgument(
+ S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(),
+ SourceLocation()));
+ Decl->setReferenced();
+ Params.emplace_back(Decl);
+ return *this;
+ }
+
Expr *getTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
TemplateTypeParmDecl *T) {
clang::ASTContext &context = S.getASTContext();
@@ -369,7 +390,7 @@ struct TemplateParameterListBuilder {
clang::CK_IntegralCast, // CastKind (e.g., Integral cast)
intLiteral, // Sub-expression being cast
nullptr, // Base path, usually null for implicit casts
- clang::VK_XValue,
+ clang::VK_LValue,
fpoo // Value kind, typically VK_RValue for implicit casts
);
@@ -380,7 +401,7 @@ struct TemplateParameterListBuilder {
implicitCastExpr, // Right-hand side expression
clang::BO_LE, // Binary operator kind (<=)
BoolTy, // Result type (bool)
- clang::VK_XValue, // Value kind
+ clang::VK_LValue, // Value kind
clang::OK_Ordinary, // Object kind
NameLoc, // Source location of operator
fpoo);
@@ -392,7 +413,10 @@ struct TemplateParameterListBuilder {
DeclContext *DC = S.CurContext;
clang::ASTContext &context = S.getASTContext();
SourceLocation NameLoc = Decl->getBeginLoc();
- IdentifierInfo *Name = Decl->getIdentifier();
+
+ IdentifierInfo &IsValidLineVectorII =
+ context.Idents.get("is_valid_line_vector");
+ IdentifierInfo &TII = context.Idents.get("T");
clang::TemplateTypeParmDecl *T = clang::TemplateTypeParmDecl::Create(
context, // AST context
@@ -401,7 +425,7 @@ struct TemplateParameterListBuilder {
NameLoc, // SourceLocation of 'T' again
/*depth=*/0, // Depth in the template parameter list
/*position=*/0, // Position in the template parameter list
- /*id=*/Name, // Identifier for 'T'
+ /*id=*/&TII, // Identifier for 'T'
/*Typename=*/true, // Indicates this is a 'typename' or 'class'
/*ParameterPack=*/false // Not a parameter pack
);
@@ -412,32 +436,33 @@ struct TemplateParameterListBuilder {
// Create and Attach Template Parameter List to ConceptDecl
llvm::ArrayRef<NamedDecl *> TemplateParamArrayRef = {T};
- clang::TemplateParameterList *Params = clang::TemplateParameterList::Create(
- context,
- NameLoc, // Source location of the template parameter list start
- NameLoc, // Source location of the template parameter list end
- TemplateParamArrayRef, // Template parameter (list as an ArrayRef)
- NameLoc, // Source location of the template parameter list within
- // concept
- nullptr // Source location of the template parameter list end within
- // concept
- );
+ clang::TemplateParameterList *ConceptParams =
+ clang::TemplateParameterList::Create(
+ context,
+ NameLoc, // Source location of the template parameter list start
+ NameLoc, // Source location of the template parameter list end
+ TemplateParamArrayRef, // Template parameter (list as an ArrayRef)
+ NameLoc, // Source location of the template parameter list within
+ // concept
+ nullptr // Source location of the template parameter list end within
+ // concept
+ );
Expr *ConstraintExpr = getTypedBufferConstraintExpr(S, NameLoc, T);
- DeclarationName DeclName = DeclarationName(Name);
+ DeclarationName DeclName = DeclarationName(&IsValidLineVectorII);
// Create a ConceptDecl
clang::ConceptDecl *conceptDecl = clang::ConceptDecl::Create(
context,
context.getTranslationUnitDecl(), // DeclContext
NameLoc, // Source location of start of concept
DeclName, // Source location of end of concept
- Params, // Template type parameter
+ ConceptParams, // Template type parameter
ConstraintExpr // Expression defining the concept
);
// Attach the template parameter list to the ConceptDecl
- conceptDecl->setTemplateParameters(Params);
+ conceptDecl->setTemplateParameters(ConceptParams);
// Add the concept declaration to the Translation Unit Decl
context.getTranslationUnitDecl()->addDecl(conceptDecl);
@@ -453,43 +478,43 @@ struct TemplateParameterListBuilder {
NestedNameSpecifierLoc NNS;
DeclContext *DC = Builder.Record->getDeclContext();
TemplateArgumentListInfo TALI(loc, loc);
- const ASTTemplateArgumentListInfo *ATALI =
- ASTTemplateArgumentListInfo::Create(context, TALI);
-
- ConceptReference *CR = ConceptReference::Create(S.getASTContext(), NNS, loc,
- DNI, CD, CD, ATALI);
- clang::TemplateTypeParmDecl *T =
- clang::TemplateTypeParmDecl::Create(
- context, // AST context
- context.getTranslationUnitDecl(), // DeclContext
- loc, // SourceLocation of 'T'
- loc, // SourceLocation of 'T' again
- /*depth=*/0, // Depth in the template parameter list
- /*position=*/0, // Position in the template parameter list
- /*id=*/Builder.Record->getIdentifier(), // Identifier for 'T'
- /*Typename=*/true, // Indicates this is a 'typename' or 'class'
- /*ParameterPack=*/false,// Not a parameter pack
- /*HasTypeConstraint=*/true // Not a parameter pack
- );
+ clang::TemplateTypeParmDecl *T = clang::TemplateTypeParmDecl::Create(
+ context, // AST context
+ context.getTranslationUnitDecl(), // 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 // Not a parameter pack
+ );
T->setDeclContext(DC);
T->setReferenced();
clang::QualType TType = context.getTypeDeclType(T);
- ArrayRef<TemplateArgument> ConvertedArgs = {TemplateArgument(TType),
- TemplateArgument(TType)};
+ ArrayRef<TemplateArgument> ConvertedArgs = {TemplateArgument(TType)};
ImplicitConceptSpecializationDecl *IDecl =
ImplicitConceptSpecializationDecl::Create(
context, Builder.Record->getDeclContext(), loc, ConvertedArgs);
const ConstraintSatisfaction CS(CD, ConvertedArgs);
+ TemplateArgumentLoc tal = S.getTrivialTemplateArgumentLoc(
+ TemplateArgument(TType), QualType(), SourceLocation());
+
+ TALI.addArgument(tal);
+ const ASTTemplateArgumentListInfo *ATALI =
+ ASTTemplateArgumentListInfo::Create(context, TALI);
+ ConceptReference *CR = ConceptReference::Create(S.getASTContext(), NNS, loc,
+ DNI, CD, CD, ATALI);
ConceptSpecializationExpr *CSE =
ConceptSpecializationExpr::Create(context, CR, IDecl, &CS);
- T->setTypeConstraint(CR, CSE);
+
return CSE;
}
@@ -519,6 +544,9 @@ struct TemplateParameterListBuilder {
QualType T = Builder.Template->getInjectedClassNameSpecialization();
T = S.Context.getInjectedClassNameType(Builder.Record, T);
+ ArrayRef<TemplateArgument> TempArgs =
+ Builder.Template->getInjectedTemplateArgs();
+
return Builder;
}
};
@@ -534,7 +562,7 @@ BuiltinTypeDeclBuilder::addSimpleTemplateParams(Sema &S,
ArrayRef<StringRef> Names) {
TemplateParameterListBuilder Builder = this->addTemplateArgumentList(S);
for (StringRef Name : Names)
- Builder.addTypeParameter(Name);
+ Builder.addTypenameTypeParameter(Name);
return Builder.finalizeTemplateArgs();
}
>From b1718c68a6025ea066e4badf8019b162dcfad68c Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Tue, 15 Oct 2024 14:04:46 -0700
Subject: [PATCH 05/16] template arguments are almost done
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 0135ff096b946d..bcfa3c591be91f 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -479,6 +479,9 @@ struct TemplateParameterListBuilder {
DeclContext *DC = Builder.Record->getDeclContext();
TemplateArgumentListInfo TALI(loc, loc);
+ TemplateTypeParmDecl *ConceptTTPD = dyn_cast<TemplateTypeParmDecl>(
+ CD->getTemplateParameters()->getParam(0));
+
clang::TemplateTypeParmDecl *T = clang::TemplateTypeParmDecl::Create(
context, // AST context
context.getTranslationUnitDecl(), // DeclContext
@@ -494,21 +497,31 @@ struct TemplateParameterListBuilder {
T->setDeclContext(DC);
T->setReferenced();
- clang::QualType TType = context.getTypeDeclType(T);
+ clang::QualType TType = context.getTypeDeclType(ConceptTTPD);
+
+ TemplateArgument TA = TemplateArgument(TType);
+
+ ArrayRef<TemplateArgument> ConvertedArgs = {TA};
- ArrayRef<TemplateArgument> ConvertedArgs = {TemplateArgument(TType)};
+ clang::QualType CSETType = context.getTypeDeclType(T);
+
+ TemplateArgument CSETA = TemplateArgument(CSETType);
+
+ ArrayRef<TemplateArgument> CSEConvertedArgs = {CSETA};
ImplicitConceptSpecializationDecl *IDecl =
ImplicitConceptSpecializationDecl::Create(
- context, Builder.Record->getDeclContext(), loc, ConvertedArgs);
+ context, Builder.Record->getDeclContext(), loc, CSEConvertedArgs);
const ConstraintSatisfaction CS(CD, ConvertedArgs);
- TemplateArgumentLoc tal = S.getTrivialTemplateArgumentLoc(
- TemplateArgument(TType), QualType(), SourceLocation());
+ TemplateArgumentLoc tal =
+ S.getTrivialTemplateArgumentLoc(TA, QualType(), SourceLocation());
TALI.addArgument(tal);
const ASTTemplateArgumentListInfo *ATALI =
ASTTemplateArgumentListInfo::Create(context, TALI);
+
+ // In CR, ATALI is what adds the extra TemplateArgument node underneath CSE
ConceptReference *CR = ConceptReference::Create(S.getASTContext(), NNS, loc,
DNI, CD, CD, ATALI);
>From 63358a1d90d6e086b22c257e8d61501ae6f07343 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Tue, 15 Oct 2024 14:26:24 -0700
Subject: [PATCH 06/16] IT WORKS! updated template arg name, just need to
remove extraneous templatetypeparmdecl
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index bcfa3c591be91f..6c490fe08b670f 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -423,9 +423,9 @@ struct TemplateParameterListBuilder {
context.getTranslationUnitDecl(), // DeclContext
NameLoc, // SourceLocation of 'T'
NameLoc, // SourceLocation of 'T' again
- /*depth=*/0, // Depth in the template parameter list
- /*position=*/0, // Position in the template parameter list
- /*id=*/&TII, // Identifier for 'T'
+ /*depth=*/0, // Depth in the template parameter list
+ /*position=*/0, // Position in the template parameter list
+ /*id=*/Params[0]->getIdentifier(), // Identifier for 'T'
/*Typename=*/true, // Indicates this is a 'typename' or 'class'
/*ParameterPack=*/false // Not a parameter pack
);
>From efaf1254baad2807f9a415418a4cd7988dc71abc Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Wed, 16 Oct 2024 11:44:01 -0700
Subject: [PATCH 07/16] break down constraint expression into simpler function
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 41 ++++++++++++-----------
1 file changed, 21 insertions(+), 20 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 6c490fe08b670f..e2db32eeddc7df 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -359,9 +359,9 @@ struct TemplateParameterListBuilder {
return *this;
}
- Expr *getTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
+ BinaryOperator *getSizeOfLEQ16Expr(clang::ASTContext &context,
+ SourceLocation NameLoc,
TemplateTypeParmDecl *T) {
- clang::ASTContext &context = S.getASTContext();
// Obtain the QualType for 'unsigned long'
clang::QualType unsignedLongType = context.UnsignedLongTy;
@@ -376,29 +376,18 @@ struct TemplateParameterListBuilder {
clang::UnaryExprOrTypeTraitExpr(clang::UETT_SizeOf, TTypeSourceInfo,
unsignedLongType, NameLoc, NameLoc);
- // Create an IntegerLiteral for the value '16'
- llvm::APInt intValue(context.getIntWidth(context.IntTy), 4);
- clang::IntegerLiteral *intLiteral = new (context)
- clang::IntegerLiteral(context, intValue, context.IntTy, NameLoc);
-
- // Create an ImplicitCastExpr to cast 'int' to 'unsigned long'
- FPOptionsOverride fpoo = FPOptionsOverride();
- clang::ImplicitCastExpr *implicitCastExpr = clang::ImplicitCastExpr::Create(
- context,
- unsignedLongType, // The type we are casting to (QualType for 'unsigned
- // long')
- clang::CK_IntegralCast, // CastKind (e.g., Integral cast)
- intLiteral, // Sub-expression being cast
- nullptr, // Base path, usually null for implicit casts
- clang::VK_LValue,
- fpoo // Value kind, typically VK_RValue for implicit casts
- );
+ // Create an IntegerLiteral for the value '16' with size type
+ clang::QualType sizeType = context.getSizeType();
+ llvm::APInt sizeValue = llvm::APInt(context.getTypeSize(sizeType), 16);
+ clang::IntegerLiteral *sizeLiteral = new (context)
+ clang::IntegerLiteral(context, sizeValue, sizeType, NameLoc);
clang::QualType BoolTy = context.BoolTy;
+ FPOptionsOverride fpoo = FPOptionsOverride();
clang::BinaryOperator *binaryOperator = clang::BinaryOperator::Create(
context, sizeofExpr, // Left-hand side expression
- implicitCastExpr, // Right-hand side expression
+ sizeLiteral, // Right-hand side expression
clang::BO_LE, // Binary operator kind (<=)
BoolTy, // Result type (bool)
clang::VK_LValue, // Value kind
@@ -409,6 +398,18 @@ struct TemplateParameterListBuilder {
return binaryOperator;
}
+ Expr *getTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
+ TemplateTypeParmDecl *T) {
+ clang::ASTContext &context = S.getASTContext();
+
+ // first get the "sizeof(T) <= 16" expression, as a binary operator
+ // TODO: add the '__builtin_hlsl_is_line_vector_layout_compatible' builtin
+ // and return a binary operator that evaluates the builtin on the given
+ // template type parameter 'T'
+ BinaryOperator *sizeOfLEQ16 = getSizeOfLEQ16Expr(context, NameLoc, T);
+ return sizeOfLEQ16;
+ }
+
ConceptDecl *getTypedBufferConceptDecl(Sema &S, CXXRecordDecl *Decl) {
DeclContext *DC = S.CurContext;
clang::ASTContext &context = S.getASTContext();
>From 01ef90694786125414c044935e9d9afc5f5cdddc Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Wed, 16 Oct 2024 12:48:09 -0700
Subject: [PATCH 08/16] remove useless function
---
.../clang/Sema/HLSLExternalSemaSource.h | 2 --
clang/lib/Sema/HLSLExternalSemaSource.cpp | 23 +------------------
2 files changed, 1 insertion(+), 24 deletions(-)
diff --git a/clang/include/clang/Sema/HLSLExternalSemaSource.h b/clang/include/clang/Sema/HLSLExternalSemaSource.h
index 0266bc0f8b336e..3c7495e66055dc 100644
--- a/clang/include/clang/Sema/HLSLExternalSemaSource.h
+++ b/clang/include/clang/Sema/HLSLExternalSemaSource.h
@@ -47,8 +47,6 @@ class HLSLExternalSemaSource : public ExternalSemaSource {
using ExternalASTSource::CompleteType;
/// Complete an incomplete HLSL builtin type
void CompleteType(TagDecl *Tag) override;
-
- ConceptDecl *getTypedBufferConceptDecl(Sema &S, CXXRecordDecl *Decl);
};
} // namespace clang
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index a502f1743aa917..4fc1472a722ce6 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -317,27 +317,6 @@ struct TemplateParameterListBuilder {
TemplateParameterListBuilder &
addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
- if (Builder.Record->isCompleteDefinition())
- return *this;
- unsigned Position = static_cast<unsigned>(Params.size());
- auto *Decl = TemplateTypeParmDecl::Create(
- S.Context, Builder.Record->getDeclContext(), SourceLocation(),
- SourceLocation(), /* TemplateDepth */ 0, Position,
- &S.Context.Idents.get(Name, tok::TokenKind::identifier),
- /* Typename */ false,
- /* ParameterPack */ false,
- /* HasTypeConstraint*/ true);
- if (!DefaultValue.isNull())
- Decl->setDefaultArgument(
- S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(),
- SourceLocation()));
-
- Params.emplace_back(Decl);
- return *this;
- }
-
- TemplateParameterListBuilder &
- addTypenameTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
if (Builder.Record->isCompleteDefinition())
return *this;
unsigned Position = static_cast<unsigned>(Params.size());
@@ -574,7 +553,7 @@ BuiltinTypeDeclBuilder::addSimpleTemplateParams(Sema &S,
ArrayRef<StringRef> Names) {
TemplateParameterListBuilder Builder = this->addTemplateArgumentList(S);
for (StringRef Name : Names)
- Builder.addTypenameTypeParameter(Name);
+ Builder.addTypeParameter(Name);
return Builder.finalizeTemplateArgs();
}
>From ee5dbc599fae7127bcee999c4e58405474f4403b Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Wed, 16 Oct 2024 13:40:15 -0700
Subject: [PATCH 09/16] some variable renaming, function rearranging
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 232 ++++++++++------------
1 file changed, 110 insertions(+), 122 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 4fc1472a722ce6..a5f41e23cb7abe 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -301,7 +301,7 @@ struct BuiltinTypeDeclBuilder {
TemplateParameterListBuilder addTemplateArgumentList(Sema &S);
BuiltinTypeDeclBuilder &addSimpleTemplateParams(Sema &S,
- ArrayRef<StringRef> Names);
+ ArrayRef<StringRef> Names, ConceptDecl *CD);
BuiltinTypeDeclBuilder &addConceptSpecializationExpr(Sema &S);
};
@@ -309,11 +309,12 @@ struct TemplateParameterListBuilder {
BuiltinTypeDeclBuilder &Builder;
Sema &S;
llvm::SmallVector<NamedDecl *> Params;
+
TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB)
: Builder(RB), S(S) {}
- ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
+ ~TemplateParameterListBuilder() { finalizeTemplateArgs(nullptr); }
TemplateParameterListBuilder &
addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
@@ -334,124 +335,11 @@ struct TemplateParameterListBuilder {
Decl->setReferenced();
Params.emplace_back(Decl);
return *this;
- }
-
- BinaryOperator *getSizeOfLEQ16Expr(clang::ASTContext &context,
- SourceLocation NameLoc,
- TemplateTypeParmDecl *T) {
- // Obtain the QualType for 'unsigned long'
- clang::QualType unsignedLongType = context.UnsignedLongTy;
-
- // Create a QualType that points to this TemplateTypeParmDecl
- clang::QualType TType = context.getTypeDeclType(T);
-
- // Create a TypeSourceInfo for the template type parameter 'T'
- clang::TypeSourceInfo *TTypeSourceInfo =
- context.getTrivialTypeSourceInfo(TType, NameLoc);
-
- clang::UnaryExprOrTypeTraitExpr *sizeofExpr = new (S.getASTContext())
- clang::UnaryExprOrTypeTraitExpr(clang::UETT_SizeOf, TTypeSourceInfo,
- unsignedLongType, NameLoc, NameLoc);
-
- // Create an IntegerLiteral for the value '16' with size type
- clang::QualType sizeType = context.getSizeType();
- llvm::APInt sizeValue = llvm::APInt(context.getTypeSize(sizeType), 16);
- clang::IntegerLiteral *sizeLiteral = new (context)
- clang::IntegerLiteral(context, sizeValue, sizeType, NameLoc);
-
- clang::QualType BoolTy = context.BoolTy;
- FPOptionsOverride fpoo = FPOptionsOverride();
-
- clang::BinaryOperator *binaryOperator = clang::BinaryOperator::Create(
- context, sizeofExpr, // Left-hand side expression
- sizeLiteral, // Right-hand side expression
- clang::BO_LE, // Binary operator kind (<=)
- BoolTy, // Result type (bool)
- clang::VK_LValue, // Value kind
- clang::OK_Ordinary, // Object kind
- NameLoc, // Source location of operator
- fpoo);
-
- return binaryOperator;
- }
-
- Expr *getTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
- TemplateTypeParmDecl *T) {
- clang::ASTContext &context = S.getASTContext();
-
- // first get the "sizeof(T) <= 16" expression, as a binary operator
- // TODO: add the '__builtin_hlsl_is_line_vector_layout_compatible' builtin
- // and return a binary operator that evaluates the builtin on the given
- // template type parameter 'T'
- BinaryOperator *sizeOfLEQ16 = getSizeOfLEQ16Expr(context, NameLoc, T);
- return sizeOfLEQ16;
- }
-
- ConceptDecl *getTypedBufferConceptDecl(Sema &S, CXXRecordDecl *Decl) {
- DeclContext *DC = S.CurContext;
- clang::ASTContext &context = S.getASTContext();
- SourceLocation NameLoc = Decl->getBeginLoc();
-
- IdentifierInfo &IsValidLineVectorII =
- context.Idents.get("is_valid_line_vector");
- IdentifierInfo &TII = context.Idents.get("T");
-
- clang::TemplateTypeParmDecl *T = clang::TemplateTypeParmDecl::Create(
- context, // AST context
- context.getTranslationUnitDecl(), // DeclContext
- NameLoc, // SourceLocation of 'T'
- NameLoc, // SourceLocation of 'T' again
- /*depth=*/0, // Depth in the template parameter list
- /*position=*/0, // Position in the template parameter list
- /*id=*/Params[0]->getIdentifier(), // Identifier for 'T'
- /*Typename=*/true, // Indicates this is a 'typename' or 'class'
- /*ParameterPack=*/false // Not a parameter pack
- );
-
- T->setDeclContext(DC);
- T->setReferenced();
+ }
- // Create and Attach Template Parameter List to ConceptDecl
-
- llvm::ArrayRef<NamedDecl *> TemplateParamArrayRef = {T};
- clang::TemplateParameterList *ConceptParams =
- clang::TemplateParameterList::Create(
- context,
- NameLoc, // Source location of the template parameter list start
- NameLoc, // Source location of the template parameter list end
- TemplateParamArrayRef, // Template parameter (list as an ArrayRef)
- NameLoc, // Source location of the template parameter list within
- // concept
- nullptr // Source location of the template parameter list end within
- // concept
- );
-
- Expr *ConstraintExpr = getTypedBufferConstraintExpr(S, NameLoc, T);
-
- DeclarationName DeclName = DeclarationName(&IsValidLineVectorII);
- // Create a ConceptDecl
- clang::ConceptDecl *conceptDecl = clang::ConceptDecl::Create(
- context,
- context.getTranslationUnitDecl(), // DeclContext
- NameLoc, // Source location of start of concept
- DeclName, // Source location of end of concept
- ConceptParams, // Template type parameter
- ConstraintExpr // Expression defining the concept
- );
-
- // Attach the template parameter list to the ConceptDecl
- conceptDecl->setTemplateParameters(ConceptParams);
-
- // Add the concept declaration to the Translation Unit Decl
- context.getTranslationUnitDecl()->addDecl(conceptDecl);
-
- return conceptDecl;
- }
-
- ConceptSpecializationExpr *getConceptSpecializationExpr(Sema &S) {
+ ConceptSpecializationExpr *getConceptSpecializationExpr(Sema &S, ConceptDecl *CD) {
ASTContext &context = S.getASTContext();
SourceLocation loc = Builder.Record->getBeginLoc();
- ConceptDecl *CD = getTypedBufferConceptDecl(S, Builder.Record);
DeclarationNameInfo DNI(CD->getDeclName(), loc);
NestedNameSpecifierLoc NNS;
DeclContext *DC = Builder.Record->getDeclContext();
@@ -509,10 +397,10 @@ struct TemplateParameterListBuilder {
return CSE;
}
- BuiltinTypeDeclBuilder &finalizeTemplateArgs() {
+ BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD) {
if (Params.empty())
return Builder;
- ConceptSpecializationExpr *CSE = getConceptSpecializationExpr(S);
+ ConceptSpecializationExpr *CSE = CD ? getConceptSpecializationExpr(S, CD) : nullptr;
auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(),
SourceLocation(), Params,
@@ -550,12 +438,12 @@ BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) {
BuiltinTypeDeclBuilder &
BuiltinTypeDeclBuilder::addSimpleTemplateParams(Sema &S,
- ArrayRef<StringRef> Names) {
+ 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() {}
@@ -666,10 +554,110 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
.addDefaultHandleConstructor(S, RC);
}
+BinaryOperator *getSizeOfLEQ16Expr(clang::ASTContext &context,
+ SourceLocation NameLoc,
+ TemplateTypeParmDecl *T) {
+ // Obtain the QualType for 'unsigned long'
+ clang::QualType unsignedLongType = context.UnsignedLongTy;
+
+ // Create a QualType that points to this TemplateTypeParmDecl
+ clang::QualType TType = context.getTypeDeclType(T);
+
+ // Create a TypeSourceInfo for the template type parameter 'T'
+ clang::TypeSourceInfo *TTypeSourceInfo =
+ context.getTrivialTypeSourceInfo(TType, NameLoc);
+
+ clang::UnaryExprOrTypeTraitExpr *sizeOfExpr = new (context)
+ clang::UnaryExprOrTypeTraitExpr(clang::UETT_SizeOf, TTypeSourceInfo,
+ unsignedLongType, NameLoc, NameLoc);
+
+ // Create an IntegerLiteral for the value '16' with size type
+ clang::QualType sizeType = context.getSizeType();
+ llvm::APInt sizeValue = llvm::APInt(context.getTypeSize(sizeType), 16);
+ clang::IntegerLiteral *sizeLiteral = new (context)
+ clang::IntegerLiteral(context, sizeValue, sizeType, NameLoc);
+
+ clang::QualType BoolTy = context.BoolTy;
+
+ clang::BinaryOperator *binaryOperator = clang::BinaryOperator::Create(
+ context, sizeOfExpr, // Left-hand side expression
+ sizeLiteral, // Right-hand side expression
+ clang::BO_LE, // Binary operator kind (<=)
+ BoolTy, // Result type (bool)
+ clang::VK_LValue, // Value kind
+ clang::OK_Ordinary, // Object kind
+ NameLoc, // Source location of operator
+ FPOptionsOverride());
+
+ return binaryOperator;
+}
+
+Expr *getTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
+ TemplateTypeParmDecl *T) {
+ clang::ASTContext &context = S.getASTContext();
+
+ // first get the "sizeof(T) <= 16" expression, as a binary operator
+ BinaryOperator *sizeOfLEQ16 = getSizeOfLEQ16Expr(context, NameLoc, T);
+ // TODO: add the '__builtin_hlsl_is_line_vector_layout_compatible' builtin
+ // and return a binary operator that evaluates the builtin on the given
+ // template type parameter 'T'
+ return sizeOfLEQ16;
+}
+
+ConceptDecl *getTypedBufferConceptDecl(Sema &S) {
+ DeclContext *DC = S.CurContext;
+ clang::ASTContext &context = S.getASTContext();
+ SourceLocation DeclLoc = SourceLocation();
+
+ IdentifierInfo &IsValidLineVectorII =
+ context.Idents.get("is_valid_line_vector");
+ IdentifierInfo &ElementTypeII =
+ context.Idents.get("element_type");
+ clang::TemplateTypeParmDecl *T = clang::TemplateTypeParmDecl::Create(
+ context, context.getTranslationUnitDecl(), 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
+ llvm::ArrayRef<NamedDecl *> TemplateParams = {T};
+ clang::TemplateParameterList *ConceptParams =
+ clang::TemplateParameterList::Create(context, DeclLoc, DeclLoc,
+ TemplateParams, DeclLoc, nullptr);
+
+ DeclarationName DeclName = DeclarationName(&IsValidLineVectorII);
+ Expr *ConstraintExpr = getTypedBufferConstraintExpr(S, DeclLoc, T);
+
+ // Create a ConceptDecl
+ clang::ConceptDecl *conceptDecl = clang::ConceptDecl::Create(
+ context,
+ context.getTranslationUnitDecl(), // DeclContext
+ DeclLoc, // Source location of start of concept
+ DeclName, // Source location of end of concept
+ ConceptParams, // Template type parameter
+ ConstraintExpr // Expression defining the concept
+ );
+
+ // Attach the template parameter list to the ConceptDecl
+ conceptDecl->setTemplateParameters(ConceptParams);
+
+ // Add the concept declaration to the Translation Unit Decl
+ context.getTranslationUnitDecl()->addDecl(conceptDecl);
+
+ return conceptDecl;
+}
+
void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
CXXRecordDecl *Decl;
+ ConceptDecl *CD = getTypedBufferConceptDecl(*SemaPtr);
+
Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
- .addSimpleTemplateParams(*SemaPtr, {"element_type"})
+ .addSimpleTemplateParams(*SemaPtr, {"element_type"}, CD)
.Record;
onCompletion(Decl, [this](CXXRecordDecl *Decl) {
>From f6ec52c31be98dbc4f6121d6f921cf27af5010fa Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Wed, 16 Oct 2024 13:42:13 -0700
Subject: [PATCH 10/16] clang format
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index a5f41e23cb7abe..5863c8df955479 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -300,8 +300,8 @@ struct BuiltinTypeDeclBuilder {
}
TemplateParameterListBuilder addTemplateArgumentList(Sema &S);
- BuiltinTypeDeclBuilder &addSimpleTemplateParams(Sema &S,
- ArrayRef<StringRef> Names, ConceptDecl *CD);
+ BuiltinTypeDeclBuilder &
+ addSimpleTemplateParams(Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD);
BuiltinTypeDeclBuilder &addConceptSpecializationExpr(Sema &S);
};
@@ -309,7 +309,6 @@ struct TemplateParameterListBuilder {
BuiltinTypeDeclBuilder &Builder;
Sema &S;
llvm::SmallVector<NamedDecl *> Params;
-
TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB)
: Builder(RB), S(S) {}
@@ -335,9 +334,10 @@ struct TemplateParameterListBuilder {
Decl->setReferenced();
Params.emplace_back(Decl);
return *this;
- }
+ }
- ConceptSpecializationExpr *getConceptSpecializationExpr(Sema &S, ConceptDecl *CD) {
+ ConceptSpecializationExpr *getConceptSpecializationExpr(Sema &S,
+ ConceptDecl *CD) {
ASTContext &context = S.getASTContext();
SourceLocation loc = Builder.Record->getBeginLoc();
DeclarationNameInfo DNI(CD->getDeclName(), loc);
@@ -400,7 +400,8 @@ struct TemplateParameterListBuilder {
BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD) {
if (Params.empty())
return Builder;
- ConceptSpecializationExpr *CSE = CD ? getConceptSpecializationExpr(S, CD) : nullptr;
+ ConceptSpecializationExpr *CSE =
+ CD ? getConceptSpecializationExpr(S, CD) : nullptr;
auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(),
SourceLocation(), Params,
@@ -436,9 +437,8 @@ BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) {
return TemplateParameterListBuilder(S, *this);
}
-BuiltinTypeDeclBuilder &
-BuiltinTypeDeclBuilder::addSimpleTemplateParams(Sema &S,
- ArrayRef<StringRef> Names, ConceptDecl *CD = nullptr) {
+BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addSimpleTemplateParams(
+ Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD = nullptr) {
TemplateParameterListBuilder Builder = this->addTemplateArgumentList(S);
for (StringRef Name : Names)
Builder.addTypeParameter(Name);
@@ -611,8 +611,7 @@ ConceptDecl *getTypedBufferConceptDecl(Sema &S) {
IdentifierInfo &IsValidLineVectorII =
context.Idents.get("is_valid_line_vector");
- IdentifierInfo &ElementTypeII =
- context.Idents.get("element_type");
+ IdentifierInfo &ElementTypeII = context.Idents.get("element_type");
clang::TemplateTypeParmDecl *T = clang::TemplateTypeParmDecl::Create(
context, context.getTranslationUnitDecl(), DeclLoc, DeclLoc,
/*depth=*/0,
>From ed2bd244fee8bfffeaa9f67c716a6df8c0b78adb Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Wed, 16 Oct 2024 14:52:44 -0700
Subject: [PATCH 11/16] fix / add test cases
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 28 ++++++++++---------
clang/test/AST/HLSL/RWBuffer-AST.hlsl | 20 +++++++++++--
clang/test/AST/HLSL/StructuredBuffer-AST.hlsl | 4 +--
clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl | 15 ++++++++--
.../SemaHLSL/BuiltIns/StructuredBuffers.hlsl | 4 +--
5 files changed, 50 insertions(+), 21 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 5863c8df955479..b2d5413f7971a9 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -341,10 +341,11 @@ struct TemplateParameterListBuilder {
ASTContext &context = S.getASTContext();
SourceLocation loc = Builder.Record->getBeginLoc();
DeclarationNameInfo DNI(CD->getDeclName(), loc);
- NestedNameSpecifierLoc NNS;
+ NestedNameSpecifierLoc NNSLoc;
DeclContext *DC = Builder.Record->getDeclContext();
TemplateArgumentListInfo TALI(loc, loc);
+ // assume that the concept decl has just one template parameter
TemplateTypeParmDecl *ConceptTTPD = dyn_cast<TemplateTypeParmDecl>(
CD->getTemplateParameters()->getParam(0));
@@ -363,11 +364,11 @@ struct TemplateParameterListBuilder {
T->setDeclContext(DC);
T->setReferenced();
- clang::QualType TType = context.getTypeDeclType(ConceptTTPD);
+ clang::QualType ConceptTType = context.getTypeDeclType(ConceptTTPD);
- TemplateArgument TA = TemplateArgument(TType);
+ TemplateArgument ConceptTA = TemplateArgument(ConceptTType);
- ArrayRef<TemplateArgument> ConvertedArgs = {TA};
+ ArrayRef<TemplateArgument> ConceptConvertedArgs = {ConceptTA};
clang::QualType CSETType = context.getTypeDeclType(T);
@@ -375,24 +376,25 @@ struct TemplateParameterListBuilder {
ArrayRef<TemplateArgument> CSEConvertedArgs = {CSETA};
- ImplicitConceptSpecializationDecl *IDecl =
+ ImplicitConceptSpecializationDecl *ImplicitCSEDecl =
ImplicitConceptSpecializationDecl::Create(
context, Builder.Record->getDeclContext(), loc, CSEConvertedArgs);
- const ConstraintSatisfaction CS(CD, ConvertedArgs);
- TemplateArgumentLoc tal =
- S.getTrivialTemplateArgumentLoc(TA, QualType(), SourceLocation());
+ const ConstraintSatisfaction CS(CD, ConceptConvertedArgs);
+ TemplateArgumentLoc TAL = S.getTrivialTemplateArgumentLoc(
+ ConceptTA, QualType(), SourceLocation());
- TALI.addArgument(tal);
+ TALI.addArgument(TAL);
const ASTTemplateArgumentListInfo *ATALI =
ASTTemplateArgumentListInfo::Create(context, TALI);
- // In CR, ATALI is what adds the extra TemplateArgument node underneath CSE
- ConceptReference *CR = ConceptReference::Create(S.getASTContext(), NNS, loc,
- DNI, CD, CD, ATALI);
+ // In the concept reference, ATALI is what adds the extra
+ // TemplateArgument node underneath CSE
+ ConceptReference *CR = ConceptReference::Create(S.getASTContext(), NNSLoc,
+ loc, DNI, CD, CD, ATALI);
ConceptSpecializationExpr *CSE =
- ConceptSpecializationExpr::Create(context, CR, IDecl, &CS);
+ ConceptSpecializationExpr::Create(context, CR, ImplicitCSEDecl, &CS);
return CSE;
}
diff --git a/clang/test/AST/HLSL/RWBuffer-AST.hlsl b/clang/test/AST/HLSL/RWBuffer-AST.hlsl
index e6ce73dbd962f7..b60519e803bb79 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> referenced 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_valid_line_vector'
+// 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> referenced 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_valid_line_vector'
+// 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 030fcfc31691dc..14784b5abb60b7 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> referenced 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> referenced 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/SemaHLSL/BuiltIns/RWBuffers.hlsl b/clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl
index 76b5d01b8036eb..9880b643852a20 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_valid_line_vector<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_valid_line_vector<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_valid_line_vector'}}
+// 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)]
>From 64e565aa51e3853f719c5de0607d8742bd3283c3 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 17 Oct 2024 11:03:52 -0700
Subject: [PATCH 12/16] add default nullptr, remove comments
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index b2d5413f7971a9..3fa764808bcefc 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -313,7 +313,7 @@ struct TemplateParameterListBuilder {
TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB)
: Builder(RB), S(S) {}
- ~TemplateParameterListBuilder() { finalizeTemplateArgs(nullptr); }
+ ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
TemplateParameterListBuilder &
addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
@@ -399,7 +399,7 @@ struct TemplateParameterListBuilder {
return CSE;
}
- BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD) {
+ BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD = nullptr) {
if (Params.empty())
return Builder;
ConceptSpecializationExpr *CSE =
@@ -636,13 +636,8 @@ ConceptDecl *getTypedBufferConceptDecl(Sema &S) {
// Create a ConceptDecl
clang::ConceptDecl *conceptDecl = clang::ConceptDecl::Create(
- context,
- context.getTranslationUnitDecl(), // DeclContext
- DeclLoc, // Source location of start of concept
- DeclName, // Source location of end of concept
- ConceptParams, // Template type parameter
- ConstraintExpr // Expression defining the concept
- );
+ context, context.getTranslationUnitDecl(), DeclLoc, DeclName,
+ ConceptParams, ConstraintExpr);
// Attach the template parameter list to the ConceptDecl
conceptDecl->setTemplateParameters(ConceptParams);
>From 83cd7f9277b29ceac90c6be2f3196b6a5896c46f Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Thu, 17 Oct 2024 16:18:52 -0700
Subject: [PATCH 13/16] remove unused var, use vector to extend memory
lifetime, may need to extend further
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 3fa764808bcefc..895db454c3cf46 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -368,13 +368,15 @@ struct TemplateParameterListBuilder {
TemplateArgument ConceptTA = TemplateArgument(ConceptTType);
- ArrayRef<TemplateArgument> ConceptConvertedArgs = {ConceptTA};
+ std::vector<TemplateArgument> ConceptConvertedArgsVec = {ConceptTA};
+ ArrayRef<TemplateArgument> ConceptConvertedArgs = ConceptConvertedArgsVec;
clang::QualType CSETType = context.getTypeDeclType(T);
TemplateArgument CSETA = TemplateArgument(CSETType);
- ArrayRef<TemplateArgument> CSEConvertedArgs = {CSETA};
+ std::vector<TemplateArgument> CSEConvertedArgsVec = {CSETA};
+ ArrayRef<TemplateArgument> CSEConvertedArgs = CSEConvertedArgsVec;
ImplicitConceptSpecializationDecl *ImplicitCSEDecl =
ImplicitConceptSpecializationDecl::Create(
@@ -426,9 +428,6 @@ struct TemplateParameterListBuilder {
QualType T = Builder.Template->getInjectedClassNameSpecialization();
T = S.Context.getInjectedClassNameType(Builder.Record, T);
- ArrayRef<TemplateArgument> TempArgs =
- Builder.Template->getInjectedTemplateArgs();
-
return Builder;
}
};
@@ -626,7 +625,9 @@ ConceptDecl *getTypedBufferConceptDecl(Sema &S) {
T->setReferenced();
// Create and Attach Template Parameter List to ConceptDecl
- llvm::ArrayRef<NamedDecl *> TemplateParams = {T};
+ std::vector<NamedDecl *> TemplateParamsVec = {T};
+ llvm::ArrayRef<NamedDecl *> TemplateParams(TemplateParamsVec);
+
clang::TemplateParameterList *ConceptParams =
clang::TemplateParameterList::Create(context, DeclLoc, DeclLoc,
TemplateParams, DeclLoc, nullptr);
>From 12e72b462f2fa516ba19870950791092c86a3b1e Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Fri, 18 Oct 2024 00:33:43 -0700
Subject: [PATCH 14/16] address everything
---
clang/lib/AST/DeclTemplate.cpp | 6 +-
clang/lib/Sema/HLSLExternalSemaSource.cpp | 67 ++++++++++++++---------
2 files changed, 44 insertions(+), 29 deletions(-)
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 515abb3f68b244..d2d8907b884ec8 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -1078,10 +1078,10 @@ ConceptDecl *ConceptDecl::Create(ASTContext &C, DeclContext *DC,
TemplateParameterList *Params,
Expr *ConstraintExpr) {
bool Invalid = AdoptTemplateParameterList(Params, DC);
- auto *CD = new (C, DC) ConceptDecl(DC, L, Name, Params, ConstraintExpr);
+ auto *TD = new (C, DC) ConceptDecl(DC, L, Name, Params, ConstraintExpr);
if (Invalid)
- CD->setInvalidDecl();
- return CD;
+ TD->setInvalidDecl();
+ return TD;
}
ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 895db454c3cf46..5126657ab0c29d 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -336,22 +336,41 @@ struct TemplateParameterListBuilder {
return *this;
}
+ /*
+ The desired result AST after this function constructs the concept
+ specialization Expression is as follows:
+
+ |-ConceptSpecializationExpr 0xdd5d408 <col:42, col:75> 'bool' Concept
+ 0xdd5d1c0 'is_valid_line_vector' | |-ImplicitConceptSpecializationDecl
+ 0xdd5d350 <line:5:9> col:9 | | `-TemplateArgument type 'type-parameter-0-0' |
+ | `-TemplateTypeParmType 0xdb90ba0 'type-parameter-0-0' dependent depth 0
+ index 0 | `-TemplateArgument <line:8:63> type
+ 'element_type':'type-parameter-0-0' | `-TemplateTypeParmType 0xdd5d2f0
+ 'element_type' dependent depth 0 index 0 | `-TemplateTypeParm 0xdd5d298
+ 'element_type'
+ */
ConceptSpecializationExpr *getConceptSpecializationExpr(Sema &S,
ConceptDecl *CD) {
- ASTContext &context = S.getASTContext();
- SourceLocation loc = Builder.Record->getBeginLoc();
- DeclarationNameInfo DNI(CD->getDeclName(), loc);
+ 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);
+ TemplateArgumentListInfo TALI(Loc, Loc);
- // assume that the concept decl has just one template parameter
+ // 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
clang::TemplateTypeParmDecl *T = clang::TemplateTypeParmDecl::Create(
- context, // AST context
- context.getTranslationUnitDecl(), // DeclContext
+ Context, // AST context
+ Context.getTranslationUnitDecl(), // DeclContext
SourceLocation(), SourceLocation(),
/*depth=*/0, // Depth in the template parameter list
/*position=*/0, // Position in the template parameter list
@@ -364,39 +383,38 @@ struct TemplateParameterListBuilder {
T->setDeclContext(DC);
T->setReferenced();
- clang::QualType ConceptTType = context.getTypeDeclType(ConceptTTPD);
+ clang::QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD);
+ // this is the 2nd template argument node in the AST above
TemplateArgument ConceptTA = TemplateArgument(ConceptTType);
- std::vector<TemplateArgument> ConceptConvertedArgsVec = {ConceptTA};
- ArrayRef<TemplateArgument> ConceptConvertedArgs = ConceptConvertedArgsVec;
-
- clang::QualType CSETType = context.getTypeDeclType(T);
+ clang::QualType CSETType = Context.getTypeDeclType(T);
+ // this is the 1st template argument node in the AST above
TemplateArgument CSETA = TemplateArgument(CSETType);
- std::vector<TemplateArgument> CSEConvertedArgsVec = {CSETA};
- ArrayRef<TemplateArgument> CSEConvertedArgs = CSEConvertedArgsVec;
-
ImplicitConceptSpecializationDecl *ImplicitCSEDecl =
ImplicitConceptSpecializationDecl::Create(
- context, Builder.Record->getDeclContext(), loc, CSEConvertedArgs);
+ Context, Builder.Record->getDeclContext(), Loc, {CSETA});
- const ConstraintSatisfaction CS(CD, ConceptConvertedArgs);
+ // 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);
+ ASTTemplateArgumentListInfo::Create(Context, TALI);
// In the concept reference, ATALI is what adds the extra
// TemplateArgument node underneath CSE
- ConceptReference *CR = ConceptReference::Create(S.getASTContext(), NNSLoc,
- loc, DNI, CD, CD, ATALI);
+ ConceptReference *CR =
+ ConceptReference::Create(Context, NNSLoc, Loc, DNI, CD, CD, ATALI);
ConceptSpecializationExpr *CSE =
- ConceptSpecializationExpr::Create(context, CR, ImplicitCSEDecl, &CS);
+ ConceptSpecializationExpr::Create(Context, CR, ImplicitCSEDecl, &CS);
return CSE;
}
@@ -625,12 +643,9 @@ ConceptDecl *getTypedBufferConceptDecl(Sema &S) {
T->setReferenced();
// Create and Attach Template Parameter List to ConceptDecl
- std::vector<NamedDecl *> TemplateParamsVec = {T};
- llvm::ArrayRef<NamedDecl *> TemplateParams(TemplateParamsVec);
-
clang::TemplateParameterList *ConceptParams =
- clang::TemplateParameterList::Create(context, DeclLoc, DeclLoc,
- TemplateParams, DeclLoc, nullptr);
+ clang::TemplateParameterList::Create(context, DeclLoc, DeclLoc, {T},
+ DeclLoc, nullptr);
DeclarationName DeclName = DeclarationName(&IsValidLineVectorII);
Expr *ConstraintExpr = getTypedBufferConstraintExpr(S, DeclLoc, T);
>From e4c87549a662586ccce667e52687e48514810010 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Fri, 18 Oct 2024 13:55:17 -0700
Subject: [PATCH 15/16] remove clang::, add c++ ast generation code, fix var
names
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 1457 +++++++++++----------
1 file changed, 731 insertions(+), 726 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 5126657ab0c29d..addfe38cd64583 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -1,726 +1,731 @@
-//===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Sema/HLSLExternalSemaSource.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/Type.h"
-#include "clang/Basic/AttrKinds.h"
-#include "clang/Basic/HLSLRuntime.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/SemaHLSL.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Frontend/HLSL/HLSLResource.h"
-
-#include <functional>
-
-using namespace clang;
-using namespace llvm::hlsl;
-
-namespace {
-
-struct TemplateParameterListBuilder;
-
-struct BuiltinTypeDeclBuilder {
- CXXRecordDecl *Record = nullptr;
- ClassTemplateDecl *Template = nullptr;
- ClassTemplateDecl *PrevTemplate = nullptr;
- NamespaceDecl *HLSLNamespace = nullptr;
- llvm::StringMap<FieldDecl *> Fields;
-
- BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) {
- Record->startDefinition();
- Template = Record->getDescribedClassTemplate();
- }
-
- BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name)
- : HLSLNamespace(Namespace) {
- ASTContext &AST = S.getASTContext();
- IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
-
- LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
- CXXRecordDecl *PrevDecl = nullptr;
- if (S.LookupQualifiedName(Result, HLSLNamespace)) {
- NamedDecl *Found = Result.getFoundDecl();
- if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
- PrevDecl = TD->getTemplatedDecl();
- PrevTemplate = TD;
- } else
- PrevDecl = dyn_cast<CXXRecordDecl>(Found);
- assert(PrevDecl && "Unexpected lookup result type.");
- }
-
- if (PrevDecl && PrevDecl->isCompleteDefinition()) {
- Record = PrevDecl;
- return;
- }
-
- Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,
- SourceLocation(), SourceLocation(), &II,
- PrevDecl, true);
- Record->setImplicit(true);
- Record->setLexicalDeclContext(HLSLNamespace);
- Record->setHasExternalLexicalStorage();
-
- // Don't let anyone derive from built-in types.
- Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
- FinalAttr::Keyword_final));
- }
-
- ~BuiltinTypeDeclBuilder() {
- if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
- HLSLNamespace->addDecl(Record);
- }
-
- BuiltinTypeDeclBuilder &
- addMemberVariable(StringRef Name, QualType Type, llvm::ArrayRef<Attr *> Attrs,
- AccessSpecifier Access = AccessSpecifier::AS_private) {
- if (Record->isCompleteDefinition())
- return *this;
- assert(Record->isBeingDefined() &&
- "Definition must be started before adding members!");
- ASTContext &AST = Record->getASTContext();
-
- IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
- TypeSourceInfo *MemTySource =
- AST.getTrivialTypeSourceInfo(Type, SourceLocation());
- auto *Field = FieldDecl::Create(
- AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
- nullptr, false, InClassInitStyle::ICIS_NoInit);
- Field->setAccess(Access);
- Field->setImplicit(true);
- for (Attr *A : Attrs) {
- if (A)
- Field->addAttr(A);
- }
-
- Record->addDecl(Field);
- Fields[Name] = Field;
- return *this;
- }
-
- BuiltinTypeDeclBuilder &
- addHandleMember(Sema &S, ResourceClass RC, ResourceKind RK, bool IsROV,
- bool RawBuffer,
- AccessSpecifier Access = AccessSpecifier::AS_private) {
- if (Record->isCompleteDefinition())
- return *this;
-
- ASTContext &Ctx = S.getASTContext();
- TypeSourceInfo *ElementTypeInfo = nullptr;
-
- QualType ElemTy = Ctx.Char8Ty;
- if (Template) {
- if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
- Template->getTemplateParameters()->getParam(0))) {
- ElemTy = QualType(TTD->getTypeForDecl(), 0);
- }
- }
- ElementTypeInfo = Ctx.getTrivialTypeSourceInfo(ElemTy, SourceLocation());
-
- // add handle member with resource type attributes
- QualType AttributedResTy = QualType();
- SmallVector<const Attr *> Attrs = {
- HLSLResourceClassAttr::CreateImplicit(Ctx, RC),
- IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
- RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
- ElementTypeInfo
- ? HLSLContainedTypeAttr::CreateImplicit(Ctx, ElementTypeInfo)
- : nullptr};
- Attr *ResourceAttr = HLSLResourceAttr::CreateImplicit(Ctx, RK);
- if (CreateHLSLAttributedResourceType(S, Ctx.HLSLResourceTy, Attrs,
- AttributedResTy))
- addMemberVariable("h", AttributedResTy, {ResourceAttr}, Access);
- return *this;
- }
-
- static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
- StringRef Name) {
- IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
- DeclarationNameInfo NameInfo =
- DeclarationNameInfo(DeclarationName(&II), SourceLocation());
- LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
- // AllowBuiltinCreation is false but LookupDirect will create
- // the builtin when searching the global scope anyways...
- S.LookupName(R, S.getCurScope());
- // FIXME: If the builtin function was user-declared in global scope,
- // this assert *will* fail. Should this call LookupBuiltin instead?
- assert(R.isSingleResult() &&
- "Since this is a builtin it should always resolve!");
- auto *VD = cast<ValueDecl>(R.getFoundDecl());
- QualType Ty = VD->getType();
- return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(),
- VD, false, NameInfo, Ty, VK_PRValue);
- }
-
- static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) {
- return IntegerLiteral::Create(
- AST,
- llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy),
- static_cast<uint8_t>(RC)),
- AST.UnsignedCharTy, SourceLocation());
- }
-
- BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S,
- ResourceClass RC) {
- if (Record->isCompleteDefinition())
- return *this;
- ASTContext &AST = Record->getASTContext();
-
- QualType ConstructorType =
- AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
-
- CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
- DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
- CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
- AST, Record, SourceLocation(),
- DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
- AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
- ExplicitSpecifier(), false, true, false,
- ConstexprSpecKind::Unspecified);
-
- Constructor->setBody(CompoundStmt::Create(
- AST, {}, FPOptionsOverride(), SourceLocation(), SourceLocation()));
- Constructor->setAccess(AccessSpecifier::AS_public);
- Record->addDecl(Constructor);
- return *this;
- }
-
- BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
- if (Record->isCompleteDefinition())
- return *this;
- addArraySubscriptOperator(true);
- addArraySubscriptOperator(false);
- return *this;
- }
-
- BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
- if (Record->isCompleteDefinition())
- return *this;
-
- ASTContext &AST = Record->getASTContext();
- QualType ElemTy = AST.Char8Ty;
- if (Template) {
- if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
- Template->getTemplateParameters()->getParam(0))) {
- ElemTy = QualType(TTD->getTypeForDecl(), 0);
- }
- }
- QualType ReturnTy = ElemTy;
-
- FunctionProtoType::ExtProtoInfo ExtInfo;
-
- // Subscript operators return references to elements, const makes the
- // reference and method const so that the underlying data is not mutable.
- ReturnTy = AST.getLValueReferenceType(ReturnTy);
- if (IsConst) {
- ExtInfo.TypeQuals.addConst();
- ReturnTy.addConst();
- }
-
- QualType MethodTy =
- AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
- auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
- auto *MethodDecl = CXXMethodDecl::Create(
- AST, Record, SourceLocation(),
- DeclarationNameInfo(
- AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
- SourceLocation()),
- MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
- SourceLocation());
-
- IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
- auto *IdxParam = ParmVarDecl::Create(
- AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
- &II, AST.UnsignedIntTy,
- AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
- SC_None, nullptr);
- MethodDecl->setParams({IdxParam});
-
- // Also add the parameter to the function prototype.
- auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
- FnProtoLoc.setParam(0, IdxParam);
-
- // FIXME: Placeholder to make sure we return the correct type - create
- // field of element_type and return reference to it. This field will go
- // away once indexing into resources is properly implemented in
- // llvm/llvm-project#95956.
- if (Fields.count("e") == 0) {
- addMemberVariable("e", ElemTy, {});
- }
- FieldDecl *ElemFieldDecl = Fields["e"];
-
- auto *This =
- CXXThisExpr::Create(AST, SourceLocation(),
- MethodDecl->getFunctionObjectParameterType(), true);
- Expr *ElemField = MemberExpr::CreateImplicit(
- AST, This, false, ElemFieldDecl, ElemFieldDecl->getType(), VK_LValue,
- OK_Ordinary);
- auto *Return =
- ReturnStmt::Create(AST, SourceLocation(), ElemField, nullptr);
-
- MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
- SourceLocation(),
- SourceLocation()));
- MethodDecl->setLexicalDeclContext(Record);
- MethodDecl->setAccess(AccessSpecifier::AS_public);
- MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
- AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
- Record->addDecl(MethodDecl);
-
- return *this;
- }
-
- BuiltinTypeDeclBuilder &startDefinition() {
- if (Record->isCompleteDefinition())
- return *this;
- Record->startDefinition();
- return *this;
- }
-
- BuiltinTypeDeclBuilder &completeDefinition() {
- if (Record->isCompleteDefinition())
- return *this;
- assert(Record->isBeingDefined() &&
- "Definition must be started before completing it.");
-
- Record->completeDefinition();
- return *this;
- }
-
- TemplateParameterListBuilder addTemplateArgumentList(Sema &S);
- BuiltinTypeDeclBuilder &
- addSimpleTemplateParams(Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD);
- BuiltinTypeDeclBuilder &addConceptSpecializationExpr(Sema &S);
-};
-
-struct TemplateParameterListBuilder {
- BuiltinTypeDeclBuilder &Builder;
- Sema &S;
- llvm::SmallVector<NamedDecl *> Params;
-
- TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB)
- : Builder(RB), S(S) {}
-
- ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
-
- TemplateParameterListBuilder &
- addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
- if (Builder.Record->isCompleteDefinition())
- return *this;
- unsigned Position = static_cast<unsigned>(Params.size());
- auto *Decl = TemplateTypeParmDecl::Create(
- S.Context, Builder.Record->getDeclContext(), SourceLocation(),
- SourceLocation(), /* TemplateDepth */ 0, Position,
- &S.Context.Idents.get(Name, tok::TokenKind::identifier),
- /* Typename */ true,
- /* ParameterPack */ false,
- /* HasTypeConstraint*/ false);
- if (!DefaultValue.isNull())
- Decl->setDefaultArgument(
- S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(),
- SourceLocation()));
- Decl->setReferenced();
- Params.emplace_back(Decl);
- return *this;
- }
-
- /*
- The desired result AST after this function constructs the concept
- specialization Expression is as follows:
-
- |-ConceptSpecializationExpr 0xdd5d408 <col:42, col:75> 'bool' Concept
- 0xdd5d1c0 'is_valid_line_vector' | |-ImplicitConceptSpecializationDecl
- 0xdd5d350 <line:5:9> col:9 | | `-TemplateArgument type 'type-parameter-0-0' |
- | `-TemplateTypeParmType 0xdb90ba0 'type-parameter-0-0' dependent depth 0
- index 0 | `-TemplateArgument <line:8:63> type
- 'element_type':'type-parameter-0-0' | `-TemplateTypeParmType 0xdd5d2f0
- 'element_type' dependent depth 0 index 0 | `-TemplateTypeParm 0xdd5d298
- 'element_type'
- */
- ConceptSpecializationExpr *getConceptSpecializationExpr(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
- clang::TemplateTypeParmDecl *T = clang::TemplateTypeParmDecl::Create(
- Context, // AST context
- Context.getTranslationUnitDecl(), // 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 // Not a parameter pack
- );
-
- T->setDeclContext(DC);
- T->setReferenced();
-
- clang::QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD);
-
- // this is the 2nd template argument node in the AST above
- TemplateArgument ConceptTA = TemplateArgument(ConceptTType);
-
- clang::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 ? getConceptSpecializationExpr(S, CD) : nullptr;
-
- auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(),
- SourceLocation(), Params,
- 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);
- Builder.Record->getDeclContext()->addDecl(Builder.Template);
- Params.clear();
-
- QualType T = Builder.Template->getInjectedClassNameSpecialization();
- T = S.Context.getInjectedClassNameType(Builder.Record, T);
-
- return Builder;
- }
-};
-} // namespace
-
-TemplateParameterListBuilder
-BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) {
- return TemplateParameterListBuilder(S, *this);
-}
-
-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(CD);
-}
-
-HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
-
-void HLSLExternalSemaSource::InitializeSema(Sema &S) {
- SemaPtr = &S;
- ASTContext &AST = SemaPtr->getASTContext();
- // If the translation unit has external storage force external decls to load.
- if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
- (void)AST.getTranslationUnitDecl()->decls_begin();
-
- IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
- LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
- NamespaceDecl *PrevDecl = nullptr;
- if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
- PrevDecl = Result.getAsSingle<NamespaceDecl>();
- HLSLNamespace = NamespaceDecl::Create(
- AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
- SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
- HLSLNamespace->setImplicit(true);
- HLSLNamespace->setHasExternalLexicalStorage();
- AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
-
- // Force external decls in the HLSL namespace to load from the PCH.
- (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
- defineTrivialHLSLTypes();
- defineHLSLTypesWithForwardDeclarations();
-
- // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
- // built in types inside a namespace, but we are planning to change that in
- // the near future. In order to be source compatible older versions of HLSL
- // will need to implicitly use the hlsl namespace. For now in clang everything
- // will get added to the namespace, and we can remove the using directive for
- // future language versions to match HLSL's evolution.
- auto *UsingDecl = UsingDirectiveDecl::Create(
- AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
- NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
- AST.getTranslationUnitDecl());
-
- AST.getTranslationUnitDecl()->addDecl(UsingDecl);
-}
-
-void HLSLExternalSemaSource::defineHLSLVectorAlias() {
- ASTContext &AST = SemaPtr->getASTContext();
-
- llvm::SmallVector<NamedDecl *> TemplateParams;
-
- auto *TypeParam = TemplateTypeParmDecl::Create(
- AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
- &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
- TypeParam->setDefaultArgument(
- AST, SemaPtr->getTrivialTemplateArgumentLoc(
- TemplateArgument(AST.FloatTy), QualType(), SourceLocation()));
-
- TemplateParams.emplace_back(TypeParam);
-
- auto *SizeParam = NonTypeTemplateParmDecl::Create(
- AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
- &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
- false, AST.getTrivialTypeSourceInfo(AST.IntTy));
- llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4);
- TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,
- /*IsDefaulted=*/true);
- SizeParam->setDefaultArgument(
- AST, SemaPtr->getTrivialTemplateArgumentLoc(Default, AST.IntTy,
- SourceLocation(), SizeParam));
- TemplateParams.emplace_back(SizeParam);
-
- auto *ParamList =
- TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
- TemplateParams, SourceLocation(), nullptr);
-
- IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
-
- QualType AliasType = AST.getDependentSizedExtVectorType(
- AST.getTemplateTypeParmType(0, 0, false, TypeParam),
- DeclRefExpr::Create(
- AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
- DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
- AST.IntTy, VK_LValue),
- SourceLocation());
-
- auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
- SourceLocation(), &II,
- AST.getTrivialTypeSourceInfo(AliasType));
- Record->setImplicit(true);
-
- auto *Template =
- TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
- Record->getIdentifier(), ParamList, Record);
-
- Record->setDescribedAliasTemplate(Template);
- Template->setImplicit(true);
- Template->setLexicalDeclContext(Record->getDeclContext());
- HLSLNamespace->addDecl(Template);
-}
-
-void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
- defineHLSLVectorAlias();
-}
-
-/// Set up common members and attributes for buffer types
-static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
- ResourceClass RC, ResourceKind RK,
- bool IsROV, bool RawBuffer) {
- return BuiltinTypeDeclBuilder(Decl)
- .addHandleMember(S, RC, RK, IsROV, RawBuffer)
- .addDefaultHandleConstructor(S, RC);
-}
-
-BinaryOperator *getSizeOfLEQ16Expr(clang::ASTContext &context,
- SourceLocation NameLoc,
- TemplateTypeParmDecl *T) {
- // Obtain the QualType for 'unsigned long'
- clang::QualType unsignedLongType = context.UnsignedLongTy;
-
- // Create a QualType that points to this TemplateTypeParmDecl
- clang::QualType TType = context.getTypeDeclType(T);
-
- // Create a TypeSourceInfo for the template type parameter 'T'
- clang::TypeSourceInfo *TTypeSourceInfo =
- context.getTrivialTypeSourceInfo(TType, NameLoc);
-
- clang::UnaryExprOrTypeTraitExpr *sizeOfExpr = new (context)
- clang::UnaryExprOrTypeTraitExpr(clang::UETT_SizeOf, TTypeSourceInfo,
- unsignedLongType, NameLoc, NameLoc);
-
- // Create an IntegerLiteral for the value '16' with size type
- clang::QualType sizeType = context.getSizeType();
- llvm::APInt sizeValue = llvm::APInt(context.getTypeSize(sizeType), 16);
- clang::IntegerLiteral *sizeLiteral = new (context)
- clang::IntegerLiteral(context, sizeValue, sizeType, NameLoc);
-
- clang::QualType BoolTy = context.BoolTy;
-
- clang::BinaryOperator *binaryOperator = clang::BinaryOperator::Create(
- context, sizeOfExpr, // Left-hand side expression
- sizeLiteral, // Right-hand side expression
- clang::BO_LE, // Binary operator kind (<=)
- BoolTy, // Result type (bool)
- clang::VK_LValue, // Value kind
- clang::OK_Ordinary, // Object kind
- NameLoc, // Source location of operator
- FPOptionsOverride());
-
- return binaryOperator;
-}
-
-Expr *getTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
- TemplateTypeParmDecl *T) {
- clang::ASTContext &context = S.getASTContext();
-
- // first get the "sizeof(T) <= 16" expression, as a binary operator
- BinaryOperator *sizeOfLEQ16 = getSizeOfLEQ16Expr(context, NameLoc, T);
- // TODO: add the '__builtin_hlsl_is_line_vector_layout_compatible' builtin
- // and return a binary operator that evaluates the builtin on the given
- // template type parameter 'T'
- return sizeOfLEQ16;
-}
-
-ConceptDecl *getTypedBufferConceptDecl(Sema &S) {
- DeclContext *DC = S.CurContext;
- clang::ASTContext &context = S.getASTContext();
- SourceLocation DeclLoc = SourceLocation();
-
- IdentifierInfo &IsValidLineVectorII =
- context.Idents.get("is_valid_line_vector");
- IdentifierInfo &ElementTypeII = context.Idents.get("element_type");
- clang::TemplateTypeParmDecl *T = clang::TemplateTypeParmDecl::Create(
- context, context.getTranslationUnitDecl(), 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
- clang::TemplateParameterList *ConceptParams =
- clang::TemplateParameterList::Create(context, DeclLoc, DeclLoc, {T},
- DeclLoc, nullptr);
-
- DeclarationName DeclName = DeclarationName(&IsValidLineVectorII);
- Expr *ConstraintExpr = getTypedBufferConstraintExpr(S, DeclLoc, T);
-
- // Create a ConceptDecl
- clang::ConceptDecl *conceptDecl = clang::ConceptDecl::Create(
- context, context.getTranslationUnitDecl(), DeclLoc, DeclName,
- ConceptParams, ConstraintExpr);
-
- // Attach the template parameter list to the ConceptDecl
- conceptDecl->setTemplateParameters(ConceptParams);
-
- // Add the concept declaration to the Translation Unit Decl
- context.getTranslationUnitDecl()->addDecl(conceptDecl);
-
- return conceptDecl;
-}
-
-void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
- CXXRecordDecl *Decl;
- ConceptDecl *CD = getTypedBufferConceptDecl(*SemaPtr);
-
- Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
- .addSimpleTemplateParams(*SemaPtr, {"element_type"}, CD)
- .Record;
-
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
- ResourceKind::TypedBuffer,
- /*IsROV=*/false, /*RawBuffer=*/false)
- .addArraySubscriptOperators()
- .completeDefinition();
- });
-
- Decl =
- BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
- .addSimpleTemplateParams(*SemaPtr, {"element_type"})
- .Record;
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
- ResourceKind::TypedBuffer, /*IsROV=*/true,
- /*RawBuffer=*/false)
- .addArraySubscriptOperators()
- .completeDefinition();
- });
-
- Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")
- .addSimpleTemplateParams(*SemaPtr, {"element_type"})
- .Record;
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
- ResourceKind::TypedBuffer, /*IsROV=*/false,
- /*RawBuffer=*/true)
- .addArraySubscriptOperators()
- .completeDefinition();
- });
-}
-
-void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
- CompletionFunction Fn) {
- Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn));
-}
-
-void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
- if (!isa<CXXRecordDecl>(Tag))
- return;
- auto Record = cast<CXXRecordDecl>(Tag);
-
- // If this is a specialization, we need to get the underlying templated
- // declaration and complete that.
- if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
- Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
- Record = Record->getCanonicalDecl();
- auto It = Completions.find(Record);
- if (It == Completions.end())
- return;
- It->second(Record);
-}
+//===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/HLSLExternalSemaSource.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/AttrKinds.h"
+#include "clang/Basic/HLSLRuntime.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaHLSL.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Frontend/HLSL/HLSLResource.h"
+
+#include <functional>
+
+using namespace clang;
+using namespace llvm::hlsl;
+
+namespace {
+
+struct TemplateParameterListBuilder;
+
+struct BuiltinTypeDeclBuilder {
+ CXXRecordDecl *Record = nullptr;
+ ClassTemplateDecl *Template = nullptr;
+ ClassTemplateDecl *PrevTemplate = nullptr;
+ NamespaceDecl *HLSLNamespace = nullptr;
+ llvm::StringMap<FieldDecl *> Fields;
+
+ BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) {
+ Record->startDefinition();
+ Template = Record->getDescribedClassTemplate();
+ }
+
+ BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name)
+ : HLSLNamespace(Namespace) {
+ ASTContext &AST = S.getASTContext();
+ IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
+
+ LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
+ CXXRecordDecl *PrevDecl = nullptr;
+ if (S.LookupQualifiedName(Result, HLSLNamespace)) {
+ NamedDecl *Found = Result.getFoundDecl();
+ if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
+ PrevDecl = TD->getTemplatedDecl();
+ PrevTemplate = TD;
+ } else
+ PrevDecl = dyn_cast<CXXRecordDecl>(Found);
+ assert(PrevDecl && "Unexpected lookup result type.");
+ }
+
+ if (PrevDecl && PrevDecl->isCompleteDefinition()) {
+ Record = PrevDecl;
+ return;
+ }
+
+ Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,
+ SourceLocation(), SourceLocation(), &II,
+ PrevDecl, true);
+ Record->setImplicit(true);
+ Record->setLexicalDeclContext(HLSLNamespace);
+ Record->setHasExternalLexicalStorage();
+
+ // Don't let anyone derive from built-in types.
+ Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
+ FinalAttr::Keyword_final));
+ }
+
+ ~BuiltinTypeDeclBuilder() {
+ if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
+ HLSLNamespace->addDecl(Record);
+ }
+
+ BuiltinTypeDeclBuilder &
+ addMemberVariable(StringRef Name, QualType Type, llvm::ArrayRef<Attr *> Attrs,
+ AccessSpecifier Access = AccessSpecifier::AS_private) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ assert(Record->isBeingDefined() &&
+ "Definition must be started before adding members!");
+ ASTContext &AST = Record->getASTContext();
+
+ IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
+ TypeSourceInfo *MemTySource =
+ AST.getTrivialTypeSourceInfo(Type, SourceLocation());
+ auto *Field = FieldDecl::Create(
+ AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
+ nullptr, false, InClassInitStyle::ICIS_NoInit);
+ Field->setAccess(Access);
+ Field->setImplicit(true);
+ for (Attr *A : Attrs) {
+ if (A)
+ Field->addAttr(A);
+ }
+
+ Record->addDecl(Field);
+ Fields[Name] = Field;
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &
+ addHandleMember(Sema &S, ResourceClass RC, ResourceKind RK, bool IsROV,
+ bool RawBuffer,
+ AccessSpecifier Access = AccessSpecifier::AS_private) {
+ if (Record->isCompleteDefinition())
+ return *this;
+
+ ASTContext &Ctx = S.getASTContext();
+ TypeSourceInfo *ElementTypeInfo = nullptr;
+
+ QualType ElemTy = Ctx.Char8Ty;
+ if (Template) {
+ if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
+ Template->getTemplateParameters()->getParam(0))) {
+ ElemTy = QualType(TTD->getTypeForDecl(), 0);
+ }
+ }
+ ElementTypeInfo = Ctx.getTrivialTypeSourceInfo(ElemTy, SourceLocation());
+
+ // add handle member with resource type attributes
+ QualType AttributedResTy = QualType();
+ SmallVector<const Attr *> Attrs = {
+ HLSLResourceClassAttr::CreateImplicit(Ctx, RC),
+ IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
+ RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
+ ElementTypeInfo
+ ? HLSLContainedTypeAttr::CreateImplicit(Ctx, ElementTypeInfo)
+ : nullptr};
+ Attr *ResourceAttr = HLSLResourceAttr::CreateImplicit(Ctx, RK);
+ if (CreateHLSLAttributedResourceType(S, Ctx.HLSLResourceTy, Attrs,
+ AttributedResTy))
+ addMemberVariable("h", AttributedResTy, {ResourceAttr}, Access);
+ return *this;
+ }
+
+ static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
+ StringRef Name) {
+ IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
+ DeclarationNameInfo NameInfo =
+ DeclarationNameInfo(DeclarationName(&II), SourceLocation());
+ LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
+ // AllowBuiltinCreation is false but LookupDirect will create
+ // the builtin when searching the global scope anyways...
+ S.LookupName(R, S.getCurScope());
+ // FIXME: If the builtin function was user-declared in global scope,
+ // this assert *will* fail. Should this call LookupBuiltin instead?
+ assert(R.isSingleResult() &&
+ "Since this is a builtin it should always resolve!");
+ auto *VD = cast<ValueDecl>(R.getFoundDecl());
+ QualType Ty = VD->getType();
+ return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(),
+ VD, false, NameInfo, Ty, VK_PRValue);
+ }
+
+ static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) {
+ return IntegerLiteral::Create(
+ AST,
+ llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy),
+ static_cast<uint8_t>(RC)),
+ AST.UnsignedCharTy, SourceLocation());
+ }
+
+ BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S,
+ ResourceClass RC) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ ASTContext &AST = Record->getASTContext();
+
+ QualType ConstructorType =
+ AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
+
+ CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
+ DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
+ CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
+ AST, Record, SourceLocation(),
+ DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
+ AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
+ ExplicitSpecifier(), false, true, false,
+ ConstexprSpecKind::Unspecified);
+
+ Constructor->setBody(CompoundStmt::Create(
+ AST, {}, FPOptionsOverride(), SourceLocation(), SourceLocation()));
+ Constructor->setAccess(AccessSpecifier::AS_public);
+ Record->addDecl(Constructor);
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
+ if (Record->isCompleteDefinition())
+ return *this;
+ addArraySubscriptOperator(true);
+ addArraySubscriptOperator(false);
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
+ if (Record->isCompleteDefinition())
+ return *this;
+
+ ASTContext &AST = Record->getASTContext();
+ QualType ElemTy = AST.Char8Ty;
+ if (Template) {
+ if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
+ Template->getTemplateParameters()->getParam(0))) {
+ ElemTy = QualType(TTD->getTypeForDecl(), 0);
+ }
+ }
+ QualType ReturnTy = ElemTy;
+
+ FunctionProtoType::ExtProtoInfo ExtInfo;
+
+ // Subscript operators return references to elements, const makes the
+ // reference and method const so that the underlying data is not mutable.
+ ReturnTy = AST.getLValueReferenceType(ReturnTy);
+ if (IsConst) {
+ ExtInfo.TypeQuals.addConst();
+ ReturnTy.addConst();
+ }
+
+ QualType MethodTy =
+ AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
+ auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
+ auto *MethodDecl = CXXMethodDecl::Create(
+ AST, Record, SourceLocation(),
+ DeclarationNameInfo(
+ AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
+ SourceLocation()),
+ MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
+ SourceLocation());
+
+ IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
+ auto *IdxParam = ParmVarDecl::Create(
+ AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
+ &II, AST.UnsignedIntTy,
+ AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
+ SC_None, nullptr);
+ MethodDecl->setParams({IdxParam});
+
+ // Also add the parameter to the function prototype.
+ auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+ FnProtoLoc.setParam(0, IdxParam);
+
+ // FIXME: Placeholder to make sure we return the correct type - create
+ // field of element_type and return reference to it. This field will go
+ // away once indexing into resources is properly implemented in
+ // llvm/llvm-project#95956.
+ if (Fields.count("e") == 0) {
+ addMemberVariable("e", ElemTy, {});
+ }
+ FieldDecl *ElemFieldDecl = Fields["e"];
+
+ auto *This =
+ CXXThisExpr::Create(AST, SourceLocation(),
+ MethodDecl->getFunctionObjectParameterType(), true);
+ Expr *ElemField = MemberExpr::CreateImplicit(
+ AST, This, false, ElemFieldDecl, ElemFieldDecl->getType(), VK_LValue,
+ OK_Ordinary);
+ auto *Return =
+ ReturnStmt::Create(AST, SourceLocation(), ElemField, nullptr);
+
+ MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
+ SourceLocation(),
+ SourceLocation()));
+ MethodDecl->setLexicalDeclContext(Record);
+ MethodDecl->setAccess(AccessSpecifier::AS_public);
+ MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
+ AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
+ Record->addDecl(MethodDecl);
+
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &startDefinition() {
+ if (Record->isCompleteDefinition())
+ return *this;
+ Record->startDefinition();
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &completeDefinition() {
+ if (Record->isCompleteDefinition())
+ return *this;
+ assert(Record->isBeingDefined() &&
+ "Definition must be started before completing it.");
+
+ Record->completeDefinition();
+ return *this;
+ }
+
+ TemplateParameterListBuilder addTemplateArgumentList(Sema &S);
+ BuiltinTypeDeclBuilder &
+ addSimpleTemplateParams(Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD);
+ BuiltinTypeDeclBuilder &addConceptSpecializationExpr(Sema &S);
+};
+
+struct TemplateParameterListBuilder {
+ BuiltinTypeDeclBuilder &Builder;
+ Sema &S;
+ llvm::SmallVector<NamedDecl *> Params;
+
+ TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB)
+ : Builder(RB), S(S) {}
+
+ ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
+
+ TemplateParameterListBuilder &
+ addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
+ if (Builder.Record->isCompleteDefinition())
+ return *this;
+ unsigned Position = static_cast<unsigned>(Params.size());
+ auto *Decl = TemplateTypeParmDecl::Create(
+ S.Context, Builder.Record->getDeclContext(), SourceLocation(),
+ SourceLocation(), /* TemplateDepth */ 0, Position,
+ &S.Context.Idents.get(Name, tok::TokenKind::identifier),
+ /* Typename */ true,
+ /* ParameterPack */ false,
+ /* HasTypeConstraint*/ false);
+ if (!DefaultValue.isNull())
+ Decl->setDefaultArgument(
+ S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(),
+ SourceLocation()));
+ Decl->setReferenced();
+ Params.emplace_back(Decl);
+ return *this;
+ }
+
+ /*
+ 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>
+ 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 *getConceptSpecializationExpr(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
+ TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
+ Context, // AST context
+ Context.getTranslationUnitDecl(), // 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 // Not a parameter pack
+ );
+
+ T->setDeclContext(DC);
+ T->setReferenced();
+
+ QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD);
+
+ // this is the 2nd template argument node in the AST above
+ 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 ? getConceptSpecializationExpr(S, CD) : nullptr;
+
+ auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(),
+ SourceLocation(), Params,
+ 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);
+ Builder.Record->getDeclContext()->addDecl(Builder.Template);
+ Params.clear();
+
+ QualType T = Builder.Template->getInjectedClassNameSpecialization();
+ T = S.Context.getInjectedClassNameType(Builder.Record, T);
+
+ return Builder;
+ }
+};
+} // namespace
+
+TemplateParameterListBuilder
+BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) {
+ return TemplateParameterListBuilder(S, *this);
+}
+
+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(CD);
+}
+
+HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
+
+void HLSLExternalSemaSource::InitializeSema(Sema &S) {
+ SemaPtr = &S;
+ ASTContext &AST = SemaPtr->getASTContext();
+ // If the translation unit has external storage force external decls to load.
+ if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
+ (void)AST.getTranslationUnitDecl()->decls_begin();
+
+ IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
+ LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
+ NamespaceDecl *PrevDecl = nullptr;
+ if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
+ PrevDecl = Result.getAsSingle<NamespaceDecl>();
+ HLSLNamespace = NamespaceDecl::Create(
+ AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
+ SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
+ HLSLNamespace->setImplicit(true);
+ HLSLNamespace->setHasExternalLexicalStorage();
+ AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
+
+ // Force external decls in the HLSL namespace to load from the PCH.
+ (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
+ defineTrivialHLSLTypes();
+ defineHLSLTypesWithForwardDeclarations();
+
+ // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
+ // built in types inside a namespace, but we are planning to change that in
+ // the near future. In order to be source compatible older versions of HLSL
+ // will need to implicitly use the hlsl namespace. For now in clang everything
+ // will get added to the namespace, and we can remove the using directive for
+ // future language versions to match HLSL's evolution.
+ auto *UsingDecl = UsingDirectiveDecl::Create(
+ AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
+ NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
+ AST.getTranslationUnitDecl());
+
+ AST.getTranslationUnitDecl()->addDecl(UsingDecl);
+}
+
+void HLSLExternalSemaSource::defineHLSLVectorAlias() {
+ ASTContext &AST = SemaPtr->getASTContext();
+
+ llvm::SmallVector<NamedDecl *> TemplateParams;
+
+ auto *TypeParam = TemplateTypeParmDecl::Create(
+ AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
+ &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
+ TypeParam->setDefaultArgument(
+ AST, SemaPtr->getTrivialTemplateArgumentLoc(
+ TemplateArgument(AST.FloatTy), QualType(), SourceLocation()));
+
+ TemplateParams.emplace_back(TypeParam);
+
+ auto *SizeParam = NonTypeTemplateParmDecl::Create(
+ AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
+ &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
+ false, AST.getTrivialTypeSourceInfo(AST.IntTy));
+ llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4);
+ TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,
+ /*IsDefaulted=*/true);
+ SizeParam->setDefaultArgument(
+ AST, SemaPtr->getTrivialTemplateArgumentLoc(Default, AST.IntTy,
+ SourceLocation(), SizeParam));
+ TemplateParams.emplace_back(SizeParam);
+
+ auto *ParamList =
+ TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
+ TemplateParams, SourceLocation(), nullptr);
+
+ IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
+
+ QualType AliasType = AST.getDependentSizedExtVectorType(
+ AST.getTemplateTypeParmType(0, 0, false, TypeParam),
+ DeclRefExpr::Create(
+ AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
+ DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
+ AST.IntTy, VK_LValue),
+ SourceLocation());
+
+ auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
+ SourceLocation(), &II,
+ AST.getTrivialTypeSourceInfo(AliasType));
+ Record->setImplicit(true);
+
+ auto *Template =
+ TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
+ Record->getIdentifier(), ParamList, Record);
+
+ Record->setDescribedAliasTemplate(Template);
+ Template->setImplicit(true);
+ Template->setLexicalDeclContext(Record->getDeclContext());
+ HLSLNamespace->addDecl(Template);
+}
+
+void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
+ defineHLSLVectorAlias();
+}
+
+/// Set up common members and attributes for buffer types
+static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
+ ResourceClass RC, ResourceKind RK,
+ bool IsROV, bool RawBuffer) {
+ return BuiltinTypeDeclBuilder(Decl)
+ .addHandleMember(S, RC, RK, IsROV, RawBuffer)
+ .addDefaultHandleConstructor(S, RC);
+}
+
+BinaryOperator *getSizeOfLEQ16Expr(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 *getTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
+ TemplateTypeParmDecl *T) {
+ ASTContext &Context = S.getASTContext();
+
+ // first get the "sizeof(T) <= 16" expression, as a binary operator
+ BinaryOperator *SizeOfLEQ16 = getSizeOfLEQ16Expr(Context, NameLoc, T);
+ // TODO: add the '__builtin_hlsl_is_line_vector_layout_compatible' builtin
+ // and return a binary operator that evaluates the builtin on the given
+ // template type parameter 'T'
+ return SizeOfLEQ16;
+}
+
+ConceptDecl *getTypedBufferConceptDecl(Sema &S) {
+ DeclContext *DC = S.CurContext;
+ ASTContext &Context = S.getASTContext();
+ SourceLocation DeclLoc = SourceLocation();
+
+ IdentifierInfo &IsValidLineVectorII =
+ Context.Idents.get("is_valid_line_vector");
+ IdentifierInfo &ElementTypeII = Context.Idents.get("element_type");
+ TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
+ Context, Context.getTranslationUnitDecl(), 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(&IsValidLineVectorII);
+ Expr *ConstraintExpr = getTypedBufferConstraintExpr(S, DeclLoc, T);
+
+ // Create a ConceptDecl
+ ConceptDecl *CD =
+ ConceptDecl::Create(Context, Context.getTranslationUnitDecl(), 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);
+
+ return CD;
+}
+
+void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
+ CXXRecordDecl *Decl;
+ ConceptDecl *CD = getTypedBufferConceptDecl(*SemaPtr);
+
+ Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
+ .addSimpleTemplateParams(*SemaPtr, {"element_type"}, CD)
+ .Record;
+
+ onCompletion(Decl, [this](CXXRecordDecl *Decl) {
+ setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
+ ResourceKind::TypedBuffer,
+ /*IsROV=*/false, /*RawBuffer=*/false)
+ .addArraySubscriptOperators()
+ .completeDefinition();
+ });
+
+ Decl =
+ BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
+ .addSimpleTemplateParams(*SemaPtr, {"element_type"})
+ .Record;
+ onCompletion(Decl, [this](CXXRecordDecl *Decl) {
+ setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
+ ResourceKind::TypedBuffer, /*IsROV=*/true,
+ /*RawBuffer=*/false)
+ .addArraySubscriptOperators()
+ .completeDefinition();
+ });
+
+ Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")
+ .addSimpleTemplateParams(*SemaPtr, {"element_type"})
+ .Record;
+ onCompletion(Decl, [this](CXXRecordDecl *Decl) {
+ setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
+ ResourceKind::TypedBuffer, /*IsROV=*/false,
+ /*RawBuffer=*/true)
+ .addArraySubscriptOperators()
+ .completeDefinition();
+ });
+}
+
+void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
+ CompletionFunction Fn) {
+ Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn));
+}
+
+void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
+ if (!isa<CXXRecordDecl>(Tag))
+ return;
+ auto Record = cast<CXXRecordDecl>(Tag);
+
+ // If this is a specialization, we need to get the underlying templated
+ // declaration and complete that.
+ if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
+ Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
+ Record = Record->getCanonicalDecl();
+ auto It = Completions.find(Record);
+ if (It == Completions.end())
+ return;
+ It->second(Record);
+}
>From a7429295546de30675b9c5d566376361dbc9d25e Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Fri, 18 Oct 2024 14:05:40 -0700
Subject: [PATCH 16/16] undo formatting problem
---
clang/lib/Sema/HLSLExternalSemaSource.cpp | 1463 +++++++++++----------
1 file changed, 732 insertions(+), 731 deletions(-)
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index addfe38cd64583..82c446c341dd34 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -1,731 +1,732 @@
-//===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Sema/HLSLExternalSemaSource.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/Type.h"
-#include "clang/Basic/AttrKinds.h"
-#include "clang/Basic/HLSLRuntime.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/SemaHLSL.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Frontend/HLSL/HLSLResource.h"
-
-#include <functional>
-
-using namespace clang;
-using namespace llvm::hlsl;
-
-namespace {
-
-struct TemplateParameterListBuilder;
-
-struct BuiltinTypeDeclBuilder {
- CXXRecordDecl *Record = nullptr;
- ClassTemplateDecl *Template = nullptr;
- ClassTemplateDecl *PrevTemplate = nullptr;
- NamespaceDecl *HLSLNamespace = nullptr;
- llvm::StringMap<FieldDecl *> Fields;
-
- BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) {
- Record->startDefinition();
- Template = Record->getDescribedClassTemplate();
- }
-
- BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name)
- : HLSLNamespace(Namespace) {
- ASTContext &AST = S.getASTContext();
- IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
-
- LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
- CXXRecordDecl *PrevDecl = nullptr;
- if (S.LookupQualifiedName(Result, HLSLNamespace)) {
- NamedDecl *Found = Result.getFoundDecl();
- if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
- PrevDecl = TD->getTemplatedDecl();
- PrevTemplate = TD;
- } else
- PrevDecl = dyn_cast<CXXRecordDecl>(Found);
- assert(PrevDecl && "Unexpected lookup result type.");
- }
-
- if (PrevDecl && PrevDecl->isCompleteDefinition()) {
- Record = PrevDecl;
- return;
- }
-
- Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,
- SourceLocation(), SourceLocation(), &II,
- PrevDecl, true);
- Record->setImplicit(true);
- Record->setLexicalDeclContext(HLSLNamespace);
- Record->setHasExternalLexicalStorage();
-
- // Don't let anyone derive from built-in types.
- Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
- FinalAttr::Keyword_final));
- }
-
- ~BuiltinTypeDeclBuilder() {
- if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
- HLSLNamespace->addDecl(Record);
- }
-
- BuiltinTypeDeclBuilder &
- addMemberVariable(StringRef Name, QualType Type, llvm::ArrayRef<Attr *> Attrs,
- AccessSpecifier Access = AccessSpecifier::AS_private) {
- if (Record->isCompleteDefinition())
- return *this;
- assert(Record->isBeingDefined() &&
- "Definition must be started before adding members!");
- ASTContext &AST = Record->getASTContext();
-
- IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
- TypeSourceInfo *MemTySource =
- AST.getTrivialTypeSourceInfo(Type, SourceLocation());
- auto *Field = FieldDecl::Create(
- AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
- nullptr, false, InClassInitStyle::ICIS_NoInit);
- Field->setAccess(Access);
- Field->setImplicit(true);
- for (Attr *A : Attrs) {
- if (A)
- Field->addAttr(A);
- }
-
- Record->addDecl(Field);
- Fields[Name] = Field;
- return *this;
- }
-
- BuiltinTypeDeclBuilder &
- addHandleMember(Sema &S, ResourceClass RC, ResourceKind RK, bool IsROV,
- bool RawBuffer,
- AccessSpecifier Access = AccessSpecifier::AS_private) {
- if (Record->isCompleteDefinition())
- return *this;
-
- ASTContext &Ctx = S.getASTContext();
- TypeSourceInfo *ElementTypeInfo = nullptr;
-
- QualType ElemTy = Ctx.Char8Ty;
- if (Template) {
- if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
- Template->getTemplateParameters()->getParam(0))) {
- ElemTy = QualType(TTD->getTypeForDecl(), 0);
- }
- }
- ElementTypeInfo = Ctx.getTrivialTypeSourceInfo(ElemTy, SourceLocation());
-
- // add handle member with resource type attributes
- QualType AttributedResTy = QualType();
- SmallVector<const Attr *> Attrs = {
- HLSLResourceClassAttr::CreateImplicit(Ctx, RC),
- IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
- RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
- ElementTypeInfo
- ? HLSLContainedTypeAttr::CreateImplicit(Ctx, ElementTypeInfo)
- : nullptr};
- Attr *ResourceAttr = HLSLResourceAttr::CreateImplicit(Ctx, RK);
- if (CreateHLSLAttributedResourceType(S, Ctx.HLSLResourceTy, Attrs,
- AttributedResTy))
- addMemberVariable("h", AttributedResTy, {ResourceAttr}, Access);
- return *this;
- }
-
- static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
- StringRef Name) {
- IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
- DeclarationNameInfo NameInfo =
- DeclarationNameInfo(DeclarationName(&II), SourceLocation());
- LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
- // AllowBuiltinCreation is false but LookupDirect will create
- // the builtin when searching the global scope anyways...
- S.LookupName(R, S.getCurScope());
- // FIXME: If the builtin function was user-declared in global scope,
- // this assert *will* fail. Should this call LookupBuiltin instead?
- assert(R.isSingleResult() &&
- "Since this is a builtin it should always resolve!");
- auto *VD = cast<ValueDecl>(R.getFoundDecl());
- QualType Ty = VD->getType();
- return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(),
- VD, false, NameInfo, Ty, VK_PRValue);
- }
-
- static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) {
- return IntegerLiteral::Create(
- AST,
- llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy),
- static_cast<uint8_t>(RC)),
- AST.UnsignedCharTy, SourceLocation());
- }
-
- BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S,
- ResourceClass RC) {
- if (Record->isCompleteDefinition())
- return *this;
- ASTContext &AST = Record->getASTContext();
-
- QualType ConstructorType =
- AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
-
- CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
- DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
- CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
- AST, Record, SourceLocation(),
- DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
- AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
- ExplicitSpecifier(), false, true, false,
- ConstexprSpecKind::Unspecified);
-
- Constructor->setBody(CompoundStmt::Create(
- AST, {}, FPOptionsOverride(), SourceLocation(), SourceLocation()));
- Constructor->setAccess(AccessSpecifier::AS_public);
- Record->addDecl(Constructor);
- return *this;
- }
-
- BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
- if (Record->isCompleteDefinition())
- return *this;
- addArraySubscriptOperator(true);
- addArraySubscriptOperator(false);
- return *this;
- }
-
- BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
- if (Record->isCompleteDefinition())
- return *this;
-
- ASTContext &AST = Record->getASTContext();
- QualType ElemTy = AST.Char8Ty;
- if (Template) {
- if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
- Template->getTemplateParameters()->getParam(0))) {
- ElemTy = QualType(TTD->getTypeForDecl(), 0);
- }
- }
- QualType ReturnTy = ElemTy;
-
- FunctionProtoType::ExtProtoInfo ExtInfo;
-
- // Subscript operators return references to elements, const makes the
- // reference and method const so that the underlying data is not mutable.
- ReturnTy = AST.getLValueReferenceType(ReturnTy);
- if (IsConst) {
- ExtInfo.TypeQuals.addConst();
- ReturnTy.addConst();
- }
-
- QualType MethodTy =
- AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
- auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
- auto *MethodDecl = CXXMethodDecl::Create(
- AST, Record, SourceLocation(),
- DeclarationNameInfo(
- AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
- SourceLocation()),
- MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
- SourceLocation());
-
- IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
- auto *IdxParam = ParmVarDecl::Create(
- AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
- &II, AST.UnsignedIntTy,
- AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
- SC_None, nullptr);
- MethodDecl->setParams({IdxParam});
-
- // Also add the parameter to the function prototype.
- auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
- FnProtoLoc.setParam(0, IdxParam);
-
- // FIXME: Placeholder to make sure we return the correct type - create
- // field of element_type and return reference to it. This field will go
- // away once indexing into resources is properly implemented in
- // llvm/llvm-project#95956.
- if (Fields.count("e") == 0) {
- addMemberVariable("e", ElemTy, {});
- }
- FieldDecl *ElemFieldDecl = Fields["e"];
-
- auto *This =
- CXXThisExpr::Create(AST, SourceLocation(),
- MethodDecl->getFunctionObjectParameterType(), true);
- Expr *ElemField = MemberExpr::CreateImplicit(
- AST, This, false, ElemFieldDecl, ElemFieldDecl->getType(), VK_LValue,
- OK_Ordinary);
- auto *Return =
- ReturnStmt::Create(AST, SourceLocation(), ElemField, nullptr);
-
- MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
- SourceLocation(),
- SourceLocation()));
- MethodDecl->setLexicalDeclContext(Record);
- MethodDecl->setAccess(AccessSpecifier::AS_public);
- MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
- AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
- Record->addDecl(MethodDecl);
-
- return *this;
- }
-
- BuiltinTypeDeclBuilder &startDefinition() {
- if (Record->isCompleteDefinition())
- return *this;
- Record->startDefinition();
- return *this;
- }
-
- BuiltinTypeDeclBuilder &completeDefinition() {
- if (Record->isCompleteDefinition())
- return *this;
- assert(Record->isBeingDefined() &&
- "Definition must be started before completing it.");
-
- Record->completeDefinition();
- return *this;
- }
-
- TemplateParameterListBuilder addTemplateArgumentList(Sema &S);
- BuiltinTypeDeclBuilder &
- addSimpleTemplateParams(Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD);
- BuiltinTypeDeclBuilder &addConceptSpecializationExpr(Sema &S);
-};
-
-struct TemplateParameterListBuilder {
- BuiltinTypeDeclBuilder &Builder;
- Sema &S;
- llvm::SmallVector<NamedDecl *> Params;
-
- TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB)
- : Builder(RB), S(S) {}
-
- ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
-
- TemplateParameterListBuilder &
- addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
- if (Builder.Record->isCompleteDefinition())
- return *this;
- unsigned Position = static_cast<unsigned>(Params.size());
- auto *Decl = TemplateTypeParmDecl::Create(
- S.Context, Builder.Record->getDeclContext(), SourceLocation(),
- SourceLocation(), /* TemplateDepth */ 0, Position,
- &S.Context.Idents.get(Name, tok::TokenKind::identifier),
- /* Typename */ true,
- /* ParameterPack */ false,
- /* HasTypeConstraint*/ false);
- if (!DefaultValue.isNull())
- Decl->setDefaultArgument(
- S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(),
- SourceLocation()));
- Decl->setReferenced();
- Params.emplace_back(Decl);
- return *this;
- }
-
- /*
- 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>
- 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 *getConceptSpecializationExpr(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
- TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
- Context, // AST context
- Context.getTranslationUnitDecl(), // 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 // Not a parameter pack
- );
-
- T->setDeclContext(DC);
- T->setReferenced();
-
- QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD);
-
- // this is the 2nd template argument node in the AST above
- 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 ? getConceptSpecializationExpr(S, CD) : nullptr;
-
- auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(),
- SourceLocation(), Params,
- 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);
- Builder.Record->getDeclContext()->addDecl(Builder.Template);
- Params.clear();
-
- QualType T = Builder.Template->getInjectedClassNameSpecialization();
- T = S.Context.getInjectedClassNameType(Builder.Record, T);
-
- return Builder;
- }
-};
-} // namespace
-
-TemplateParameterListBuilder
-BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) {
- return TemplateParameterListBuilder(S, *this);
-}
-
-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(CD);
-}
-
-HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
-
-void HLSLExternalSemaSource::InitializeSema(Sema &S) {
- SemaPtr = &S;
- ASTContext &AST = SemaPtr->getASTContext();
- // If the translation unit has external storage force external decls to load.
- if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
- (void)AST.getTranslationUnitDecl()->decls_begin();
-
- IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
- LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
- NamespaceDecl *PrevDecl = nullptr;
- if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
- PrevDecl = Result.getAsSingle<NamespaceDecl>();
- HLSLNamespace = NamespaceDecl::Create(
- AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
- SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
- HLSLNamespace->setImplicit(true);
- HLSLNamespace->setHasExternalLexicalStorage();
- AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
-
- // Force external decls in the HLSL namespace to load from the PCH.
- (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
- defineTrivialHLSLTypes();
- defineHLSLTypesWithForwardDeclarations();
-
- // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
- // built in types inside a namespace, but we are planning to change that in
- // the near future. In order to be source compatible older versions of HLSL
- // will need to implicitly use the hlsl namespace. For now in clang everything
- // will get added to the namespace, and we can remove the using directive for
- // future language versions to match HLSL's evolution.
- auto *UsingDecl = UsingDirectiveDecl::Create(
- AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
- NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
- AST.getTranslationUnitDecl());
-
- AST.getTranslationUnitDecl()->addDecl(UsingDecl);
-}
-
-void HLSLExternalSemaSource::defineHLSLVectorAlias() {
- ASTContext &AST = SemaPtr->getASTContext();
-
- llvm::SmallVector<NamedDecl *> TemplateParams;
-
- auto *TypeParam = TemplateTypeParmDecl::Create(
- AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
- &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
- TypeParam->setDefaultArgument(
- AST, SemaPtr->getTrivialTemplateArgumentLoc(
- TemplateArgument(AST.FloatTy), QualType(), SourceLocation()));
-
- TemplateParams.emplace_back(TypeParam);
-
- auto *SizeParam = NonTypeTemplateParmDecl::Create(
- AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
- &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
- false, AST.getTrivialTypeSourceInfo(AST.IntTy));
- llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4);
- TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,
- /*IsDefaulted=*/true);
- SizeParam->setDefaultArgument(
- AST, SemaPtr->getTrivialTemplateArgumentLoc(Default, AST.IntTy,
- SourceLocation(), SizeParam));
- TemplateParams.emplace_back(SizeParam);
-
- auto *ParamList =
- TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
- TemplateParams, SourceLocation(), nullptr);
-
- IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
-
- QualType AliasType = AST.getDependentSizedExtVectorType(
- AST.getTemplateTypeParmType(0, 0, false, TypeParam),
- DeclRefExpr::Create(
- AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
- DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
- AST.IntTy, VK_LValue),
- SourceLocation());
-
- auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
- SourceLocation(), &II,
- AST.getTrivialTypeSourceInfo(AliasType));
- Record->setImplicit(true);
-
- auto *Template =
- TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
- Record->getIdentifier(), ParamList, Record);
-
- Record->setDescribedAliasTemplate(Template);
- Template->setImplicit(true);
- Template->setLexicalDeclContext(Record->getDeclContext());
- HLSLNamespace->addDecl(Template);
-}
-
-void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
- defineHLSLVectorAlias();
-}
-
-/// Set up common members and attributes for buffer types
-static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
- ResourceClass RC, ResourceKind RK,
- bool IsROV, bool RawBuffer) {
- return BuiltinTypeDeclBuilder(Decl)
- .addHandleMember(S, RC, RK, IsROV, RawBuffer)
- .addDefaultHandleConstructor(S, RC);
-}
-
-BinaryOperator *getSizeOfLEQ16Expr(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 *getTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
- TemplateTypeParmDecl *T) {
- ASTContext &Context = S.getASTContext();
-
- // first get the "sizeof(T) <= 16" expression, as a binary operator
- BinaryOperator *SizeOfLEQ16 = getSizeOfLEQ16Expr(Context, NameLoc, T);
- // TODO: add the '__builtin_hlsl_is_line_vector_layout_compatible' builtin
- // and return a binary operator that evaluates the builtin on the given
- // template type parameter 'T'
- return SizeOfLEQ16;
-}
-
-ConceptDecl *getTypedBufferConceptDecl(Sema &S) {
- DeclContext *DC = S.CurContext;
- ASTContext &Context = S.getASTContext();
- SourceLocation DeclLoc = SourceLocation();
-
- IdentifierInfo &IsValidLineVectorII =
- Context.Idents.get("is_valid_line_vector");
- IdentifierInfo &ElementTypeII = Context.Idents.get("element_type");
- TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
- Context, Context.getTranslationUnitDecl(), 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(&IsValidLineVectorII);
- Expr *ConstraintExpr = getTypedBufferConstraintExpr(S, DeclLoc, T);
-
- // Create a ConceptDecl
- ConceptDecl *CD =
- ConceptDecl::Create(Context, Context.getTranslationUnitDecl(), 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);
-
- return CD;
-}
-
-void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
- CXXRecordDecl *Decl;
- ConceptDecl *CD = getTypedBufferConceptDecl(*SemaPtr);
-
- Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
- .addSimpleTemplateParams(*SemaPtr, {"element_type"}, CD)
- .Record;
-
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
- ResourceKind::TypedBuffer,
- /*IsROV=*/false, /*RawBuffer=*/false)
- .addArraySubscriptOperators()
- .completeDefinition();
- });
-
- Decl =
- BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
- .addSimpleTemplateParams(*SemaPtr, {"element_type"})
- .Record;
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
- ResourceKind::TypedBuffer, /*IsROV=*/true,
- /*RawBuffer=*/false)
- .addArraySubscriptOperators()
- .completeDefinition();
- });
-
- Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")
- .addSimpleTemplateParams(*SemaPtr, {"element_type"})
- .Record;
- onCompletion(Decl, [this](CXXRecordDecl *Decl) {
- setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
- ResourceKind::TypedBuffer, /*IsROV=*/false,
- /*RawBuffer=*/true)
- .addArraySubscriptOperators()
- .completeDefinition();
- });
-}
-
-void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
- CompletionFunction Fn) {
- Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn));
-}
-
-void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
- if (!isa<CXXRecordDecl>(Tag))
- return;
- auto Record = cast<CXXRecordDecl>(Tag);
-
- // If this is a specialization, we need to get the underlying templated
- // declaration and complete that.
- if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
- Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
- Record = Record->getCanonicalDecl();
- auto It = Completions.find(Record);
- if (It == Completions.end())
- return;
- It->second(Record);
-}
+//===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/HLSLExternalSemaSource.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/AttrKinds.h"
+#include "clang/Basic/HLSLRuntime.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaHLSL.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Frontend/HLSL/HLSLResource.h"
+
+#include <functional>
+
+using namespace clang;
+using namespace llvm::hlsl;
+
+namespace {
+
+struct TemplateParameterListBuilder;
+
+struct BuiltinTypeDeclBuilder {
+ CXXRecordDecl *Record = nullptr;
+ ClassTemplateDecl *Template = nullptr;
+ ClassTemplateDecl *PrevTemplate = nullptr;
+ NamespaceDecl *HLSLNamespace = nullptr;
+ llvm::StringMap<FieldDecl *> Fields;
+
+ BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) {
+ Record->startDefinition();
+ Template = Record->getDescribedClassTemplate();
+ }
+
+ BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name)
+ : HLSLNamespace(Namespace) {
+ ASTContext &AST = S.getASTContext();
+ IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
+
+ LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
+ CXXRecordDecl *PrevDecl = nullptr;
+ if (S.LookupQualifiedName(Result, HLSLNamespace)) {
+ NamedDecl *Found = Result.getFoundDecl();
+ if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
+ PrevDecl = TD->getTemplatedDecl();
+ PrevTemplate = TD;
+ } else
+ PrevDecl = dyn_cast<CXXRecordDecl>(Found);
+ assert(PrevDecl && "Unexpected lookup result type.");
+ }
+
+ if (PrevDecl && PrevDecl->isCompleteDefinition()) {
+ Record = PrevDecl;
+ return;
+ }
+
+ Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,
+ SourceLocation(), SourceLocation(), &II,
+ PrevDecl, true);
+ Record->setImplicit(true);
+ Record->setLexicalDeclContext(HLSLNamespace);
+ Record->setHasExternalLexicalStorage();
+
+ // Don't let anyone derive from built-in types.
+ Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
+ FinalAttr::Keyword_final));
+ }
+
+ ~BuiltinTypeDeclBuilder() {
+ if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
+ HLSLNamespace->addDecl(Record);
+ }
+
+ BuiltinTypeDeclBuilder &
+ addMemberVariable(StringRef Name, QualType Type, llvm::ArrayRef<Attr *> Attrs,
+ AccessSpecifier Access = AccessSpecifier::AS_private) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ assert(Record->isBeingDefined() &&
+ "Definition must be started before adding members!");
+ ASTContext &AST = Record->getASTContext();
+
+ IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
+ TypeSourceInfo *MemTySource =
+ AST.getTrivialTypeSourceInfo(Type, SourceLocation());
+ auto *Field = FieldDecl::Create(
+ AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
+ nullptr, false, InClassInitStyle::ICIS_NoInit);
+ Field->setAccess(Access);
+ Field->setImplicit(true);
+ for (Attr *A : Attrs) {
+ if (A)
+ Field->addAttr(A);
+ }
+
+ Record->addDecl(Field);
+ Fields[Name] = Field;
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &
+ addHandleMember(Sema &S, ResourceClass RC, ResourceKind RK, bool IsROV,
+ bool RawBuffer,
+ AccessSpecifier Access = AccessSpecifier::AS_private) {
+ if (Record->isCompleteDefinition())
+ return *this;
+
+ ASTContext &Ctx = S.getASTContext();
+ TypeSourceInfo *ElementTypeInfo = nullptr;
+
+ QualType ElemTy = Ctx.Char8Ty;
+ if (Template) {
+ if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
+ Template->getTemplateParameters()->getParam(0))) {
+ ElemTy = QualType(TTD->getTypeForDecl(), 0);
+ }
+ }
+ ElementTypeInfo = Ctx.getTrivialTypeSourceInfo(ElemTy, SourceLocation());
+
+ // add handle member with resource type attributes
+ QualType AttributedResTy = QualType();
+ SmallVector<const Attr *> Attrs = {
+ HLSLResourceClassAttr::CreateImplicit(Ctx, RC),
+ IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
+ RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
+ ElementTypeInfo
+ ? HLSLContainedTypeAttr::CreateImplicit(Ctx, ElementTypeInfo)
+ : nullptr};
+ Attr *ResourceAttr = HLSLResourceAttr::CreateImplicit(Ctx, RK);
+ if (CreateHLSLAttributedResourceType(S, Ctx.HLSLResourceTy, Attrs,
+ AttributedResTy))
+ addMemberVariable("h", AttributedResTy, {ResourceAttr}, Access);
+ return *this;
+ }
+
+ static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
+ StringRef Name) {
+ IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
+ DeclarationNameInfo NameInfo =
+ DeclarationNameInfo(DeclarationName(&II), SourceLocation());
+ LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
+ // AllowBuiltinCreation is false but LookupDirect will create
+ // the builtin when searching the global scope anyways...
+ S.LookupName(R, S.getCurScope());
+ // FIXME: If the builtin function was user-declared in global scope,
+ // this assert *will* fail. Should this call LookupBuiltin instead?
+ assert(R.isSingleResult() &&
+ "Since this is a builtin it should always resolve!");
+ auto *VD = cast<ValueDecl>(R.getFoundDecl());
+ QualType Ty = VD->getType();
+ return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(),
+ VD, false, NameInfo, Ty, VK_PRValue);
+ }
+
+ static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) {
+ return IntegerLiteral::Create(
+ AST,
+ llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy),
+ static_cast<uint8_t>(RC)),
+ AST.UnsignedCharTy, SourceLocation());
+ }
+
+ BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S,
+ ResourceClass RC) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ ASTContext &AST = Record->getASTContext();
+
+ QualType ConstructorType =
+ AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
+
+ CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
+ DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
+ CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
+ AST, Record, SourceLocation(),
+ DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
+ AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
+ ExplicitSpecifier(), false, true, false,
+ ConstexprSpecKind::Unspecified);
+
+ Constructor->setBody(CompoundStmt::Create(
+ AST, {}, FPOptionsOverride(), SourceLocation(), SourceLocation()));
+ Constructor->setAccess(AccessSpecifier::AS_public);
+ Record->addDecl(Constructor);
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
+ if (Record->isCompleteDefinition())
+ return *this;
+ addArraySubscriptOperator(true);
+ addArraySubscriptOperator(false);
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
+ if (Record->isCompleteDefinition())
+ return *this;
+
+ ASTContext &AST = Record->getASTContext();
+ QualType ElemTy = AST.Char8Ty;
+ if (Template) {
+ if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
+ Template->getTemplateParameters()->getParam(0))) {
+ ElemTy = QualType(TTD->getTypeForDecl(), 0);
+ }
+ }
+ QualType ReturnTy = ElemTy;
+
+ FunctionProtoType::ExtProtoInfo ExtInfo;
+
+ // Subscript operators return references to elements, const makes the
+ // reference and method const so that the underlying data is not mutable.
+ ReturnTy = AST.getLValueReferenceType(ReturnTy);
+ if (IsConst) {
+ ExtInfo.TypeQuals.addConst();
+ ReturnTy.addConst();
+ }
+
+ QualType MethodTy =
+ AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
+ auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
+ auto *MethodDecl = CXXMethodDecl::Create(
+ AST, Record, SourceLocation(),
+ DeclarationNameInfo(
+ AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
+ SourceLocation()),
+ MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
+ SourceLocation());
+
+ IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
+ auto *IdxParam = ParmVarDecl::Create(
+ AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
+ &II, AST.UnsignedIntTy,
+ AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
+ SC_None, nullptr);
+ MethodDecl->setParams({IdxParam});
+
+ // Also add the parameter to the function prototype.
+ auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+ FnProtoLoc.setParam(0, IdxParam);
+
+ // FIXME: Placeholder to make sure we return the correct type - create
+ // field of element_type and return reference to it. This field will go
+ // away once indexing into resources is properly implemented in
+ // llvm/llvm-project#95956.
+ if (Fields.count("e") == 0) {
+ addMemberVariable("e", ElemTy, {});
+ }
+ FieldDecl *ElemFieldDecl = Fields["e"];
+
+ auto *This =
+ CXXThisExpr::Create(AST, SourceLocation(),
+ MethodDecl->getFunctionObjectParameterType(), true);
+ Expr *ElemField = MemberExpr::CreateImplicit(
+ AST, This, false, ElemFieldDecl, ElemFieldDecl->getType(), VK_LValue,
+ OK_Ordinary);
+ auto *Return =
+ ReturnStmt::Create(AST, SourceLocation(), ElemField, nullptr);
+
+ MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
+ SourceLocation(),
+ SourceLocation()));
+ MethodDecl->setLexicalDeclContext(Record);
+ MethodDecl->setAccess(AccessSpecifier::AS_public);
+ MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
+ AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
+ Record->addDecl(MethodDecl);
+
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &startDefinition() {
+ if (Record->isCompleteDefinition())
+ return *this;
+ Record->startDefinition();
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &completeDefinition() {
+ if (Record->isCompleteDefinition())
+ return *this;
+ assert(Record->isBeingDefined() &&
+ "Definition must be started before completing it.");
+
+ Record->completeDefinition();
+ return *this;
+ }
+
+ TemplateParameterListBuilder addTemplateArgumentList(Sema &S);
+ BuiltinTypeDeclBuilder &
+ addSimpleTemplateParams(Sema &S, ArrayRef<StringRef> Names, ConceptDecl *CD);
+ BuiltinTypeDeclBuilder &addConceptSpecializationExpr(Sema &S);
+};
+
+struct TemplateParameterListBuilder {
+ BuiltinTypeDeclBuilder &Builder;
+ Sema &S;
+ llvm::SmallVector<NamedDecl *> Params;
+
+ TemplateParameterListBuilder(Sema &S, BuiltinTypeDeclBuilder &RB)
+ : Builder(RB), S(S) {}
+
+ ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
+
+ TemplateParameterListBuilder &
+ addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
+ if (Builder.Record->isCompleteDefinition())
+ return *this;
+ unsigned Position = static_cast<unsigned>(Params.size());
+ auto *Decl = TemplateTypeParmDecl::Create(
+ S.Context, Builder.Record->getDeclContext(), SourceLocation(),
+ SourceLocation(), /* TemplateDepth */ 0, Position,
+ &S.Context.Idents.get(Name, tok::TokenKind::identifier),
+ /* Typename */ true,
+ /* ParameterPack */ false,
+ /* HasTypeConstraint*/ false);
+ if (!DefaultValue.isNull())
+ Decl->setDefaultArgument(
+ S.Context, S.getTrivialTemplateArgumentLoc(DefaultValue, QualType(),
+ SourceLocation()));
+ Decl->setReferenced();
+ Params.emplace_back(Decl);
+ return *this;
+ }
+
+ /*
+ 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>
+
+ 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 *getConceptSpecializationExpr(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
+ TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
+ Context, // AST context
+ Context.getTranslationUnitDecl(), // 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();
+
+ QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD);
+
+ // this is the 2nd template argument node in the AST above
+ 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 ? getConceptSpecializationExpr(S, CD) : nullptr;
+
+ auto *ParamList = TemplateParameterList::Create(S.Context, SourceLocation(),
+ SourceLocation(), Params,
+ 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);
+ Builder.Record->getDeclContext()->addDecl(Builder.Template);
+ Params.clear();
+
+ QualType T = Builder.Template->getInjectedClassNameSpecialization();
+ T = S.Context.getInjectedClassNameType(Builder.Record, T);
+
+ return Builder;
+ }
+};
+} // namespace
+
+TemplateParameterListBuilder
+BuiltinTypeDeclBuilder::addTemplateArgumentList(Sema &S) {
+ return TemplateParameterListBuilder(S, *this);
+}
+
+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(CD);
+}
+
+HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
+
+void HLSLExternalSemaSource::InitializeSema(Sema &S) {
+ SemaPtr = &S;
+ ASTContext &AST = SemaPtr->getASTContext();
+ // If the translation unit has external storage force external decls to load.
+ if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
+ (void)AST.getTranslationUnitDecl()->decls_begin();
+
+ IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
+ LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
+ NamespaceDecl *PrevDecl = nullptr;
+ if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
+ PrevDecl = Result.getAsSingle<NamespaceDecl>();
+ HLSLNamespace = NamespaceDecl::Create(
+ AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
+ SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
+ HLSLNamespace->setImplicit(true);
+ HLSLNamespace->setHasExternalLexicalStorage();
+ AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
+
+ // Force external decls in the HLSL namespace to load from the PCH.
+ (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
+ defineTrivialHLSLTypes();
+ defineHLSLTypesWithForwardDeclarations();
+
+ // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
+ // built in types inside a namespace, but we are planning to change that in
+ // the near future. In order to be source compatible older versions of HLSL
+ // will need to implicitly use the hlsl namespace. For now in clang everything
+ // will get added to the namespace, and we can remove the using directive for
+ // future language versions to match HLSL's evolution.
+ auto *UsingDecl = UsingDirectiveDecl::Create(
+ AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
+ NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
+ AST.getTranslationUnitDecl());
+
+ AST.getTranslationUnitDecl()->addDecl(UsingDecl);
+}
+
+void HLSLExternalSemaSource::defineHLSLVectorAlias() {
+ ASTContext &AST = SemaPtr->getASTContext();
+
+ llvm::SmallVector<NamedDecl *> TemplateParams;
+
+ auto *TypeParam = TemplateTypeParmDecl::Create(
+ AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
+ &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
+ TypeParam->setDefaultArgument(
+ AST, SemaPtr->getTrivialTemplateArgumentLoc(
+ TemplateArgument(AST.FloatTy), QualType(), SourceLocation()));
+
+ TemplateParams.emplace_back(TypeParam);
+
+ auto *SizeParam = NonTypeTemplateParmDecl::Create(
+ AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
+ &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
+ false, AST.getTrivialTypeSourceInfo(AST.IntTy));
+ llvm::APInt Val(AST.getIntWidth(AST.IntTy), 4);
+ TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,
+ /*IsDefaulted=*/true);
+ SizeParam->setDefaultArgument(
+ AST, SemaPtr->getTrivialTemplateArgumentLoc(Default, AST.IntTy,
+ SourceLocation(), SizeParam));
+ TemplateParams.emplace_back(SizeParam);
+
+ auto *ParamList =
+ TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
+ TemplateParams, SourceLocation(), nullptr);
+
+ IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
+
+ QualType AliasType = AST.getDependentSizedExtVectorType(
+ AST.getTemplateTypeParmType(0, 0, false, TypeParam),
+ DeclRefExpr::Create(
+ AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
+ DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
+ AST.IntTy, VK_LValue),
+ SourceLocation());
+
+ auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
+ SourceLocation(), &II,
+ AST.getTrivialTypeSourceInfo(AliasType));
+ Record->setImplicit(true);
+
+ auto *Template =
+ TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
+ Record->getIdentifier(), ParamList, Record);
+
+ Record->setDescribedAliasTemplate(Template);
+ Template->setImplicit(true);
+ Template->setLexicalDeclContext(Record->getDeclContext());
+ HLSLNamespace->addDecl(Template);
+}
+
+void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
+ defineHLSLVectorAlias();
+}
+
+/// Set up common members and attributes for buffer types
+static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
+ ResourceClass RC, ResourceKind RK,
+ bool IsROV, bool RawBuffer) {
+ return BuiltinTypeDeclBuilder(Decl)
+ .addHandleMember(S, RC, RK, IsROV, RawBuffer)
+ .addDefaultHandleConstructor(S, RC);
+}
+
+BinaryOperator *getSizeOfLEQ16Expr(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(
+ clang::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
+ clang::BO_LE, // Binary operator kind (<=)
+ BoolTy, // Result type (bool)
+ clang::VK_LValue, // Value kind
+ clang::OK_Ordinary, // Object kind
+ NameLoc, // Source location of operator
+ FPOptionsOverride());
+
+ return binaryOperator;
+}
+
+Expr *getTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
+ TemplateTypeParmDecl *T) {
+ ASTContext &Context = S.getASTContext();
+
+ // first get the "sizeof(T) <= 16" expression, as a binary operator
+ BinaryOperator *SizeOfLEQ16 = getSizeOfLEQ16Expr(Context, NameLoc, T);
+ // TODO: add the '__builtin_hlsl_is_line_vector_layout_compatible' builtin
+ // and return a binary operator that evaluates the builtin on the given
+ // template type parameter 'T'
+ return SizeOfLEQ16;
+}
+
+ConceptDecl *getTypedBufferConceptDecl(Sema &S) {
+ DeclContext *DC = S.CurContext;
+ ASTContext &Context = S.getASTContext();
+ SourceLocation DeclLoc = SourceLocation();
+
+ IdentifierInfo &IsValidLineVectorII =
+ Context.Idents.get("is_valid_line_vector");
+ IdentifierInfo &ElementTypeII = Context.Idents.get("element_type");
+ TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
+ Context, Context.getTranslationUnitDecl(), 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(&IsValidLineVectorII);
+ Expr *ConstraintExpr = getTypedBufferConstraintExpr(S, DeclLoc, T);
+
+ // Create a ConceptDecl
+ ConceptDecl *CD =
+ ConceptDecl::Create(Context, Context.getTranslationUnitDecl(), 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);
+
+ return CD;
+}
+
+void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
+ CXXRecordDecl *Decl;
+ ConceptDecl *CD = getTypedBufferConceptDecl(*SemaPtr);
+
+ Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
+ .addSimpleTemplateParams(*SemaPtr, {"element_type"}, CD)
+ .Record;
+
+ onCompletion(Decl, [this](CXXRecordDecl *Decl) {
+ setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
+ ResourceKind::TypedBuffer,
+ /*IsROV=*/false, /*RawBuffer=*/false)
+ .addArraySubscriptOperators()
+ .completeDefinition();
+ });
+
+ Decl =
+ BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
+ .addSimpleTemplateParams(*SemaPtr, {"element_type"})
+ .Record;
+ onCompletion(Decl, [this](CXXRecordDecl *Decl) {
+ setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
+ ResourceKind::TypedBuffer, /*IsROV=*/true,
+ /*RawBuffer=*/false)
+ .addArraySubscriptOperators()
+ .completeDefinition();
+ });
+
+ Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")
+ .addSimpleTemplateParams(*SemaPtr, {"element_type"})
+ .Record;
+ onCompletion(Decl, [this](CXXRecordDecl *Decl) {
+ setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
+ ResourceKind::TypedBuffer, /*IsROV=*/false,
+ /*RawBuffer=*/true)
+ .addArraySubscriptOperators()
+ .completeDefinition();
+ });
+}
+
+void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
+ CompletionFunction Fn) {
+ Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn));
+}
+
+void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
+ if (!isa<CXXRecordDecl>(Tag))
+ return;
+ auto Record = cast<CXXRecordDecl>(Tag);
+
+ // If this is a specialization, we need to get the underlying templated
+ // declaration and complete that.
+ if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
+ Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
+ Record = Record->getCanonicalDecl();
+ auto It = Completions.find(Record);
+ if (It == Completions.end())
+ return;
+ It->second(Record);
+}
More information about the cfe-commits
mailing list