Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 166 additions & 16 deletions clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaHLSL.h"
Expand Down Expand Up @@ -110,8 +111,11 @@ struct BuiltinTypeMethodBuilder {
CXXMethodDecl *Method;
bool IsConst;
bool IsCtor;
AccessSpecifier Access;
StorageClass SC;
llvm::SmallVector<Param> Params;
llvm::SmallVector<Stmt *> StmtsList;
llvm::SmallVector<VarDecl *> LocalVars;

// Argument placeholders, inspired by std::placeholder. These are the indices
// of arguments to forward to `callBuiltin` and other method builder methods.
Expand All @@ -120,7 +124,16 @@ struct BuiltinTypeMethodBuilder {
// LastStmt - refers to the last statement in the method body; referencing
// LastStmt will remove the statement from the method body since
// it will be linked from the new expression being constructed.
enum class PlaceHolder { _0, _1, _2, _3, _4, Handle = 128, LastStmt };
enum class PlaceHolder {
_0,
_1,
_2,
_3,
_4,
LocalVar_0 = 64,
Handle = 128,
LastStmt
};

Expr *convertPlaceholder(PlaceHolder PH);
Expr *convertPlaceholder(Expr *E) { return E; }
Expand All @@ -130,13 +143,17 @@ struct BuiltinTypeMethodBuilder {

BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name,
QualType ReturnTy, bool IsConst = false,
bool IsCtor = false)
bool IsCtor = false,
AccessSpecifier Access = AS_public,
StorageClass SC = SC_None)
: DeclBuilder(DB), Name(Name), ReturnTy(ReturnTy), Method(nullptr),
IsConst(IsConst), IsCtor(IsCtor) {}
IsConst(IsConst), IsCtor(IsCtor), Access(Access), SC(SC) {}

BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr,
QualType ReturnTy, bool IsConst = false,
bool IsCtor = false);
bool IsCtor = false,
AccessSpecifier Access = AS_public,
StorageClass SC = SC_None);
BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;

~BuiltinTypeMethodBuilder() { finalize(); }
Expand All @@ -147,12 +164,19 @@ struct BuiltinTypeMethodBuilder {
BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty,
HLSLParamModifierAttr::Spelling Modifier =
HLSLParamModifierAttr::Keyword_in);
BuiltinTypeMethodBuilder &createLocalVar(StringRef Name, QualType Ty);
template <typename... Ts>
BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
QualType ReturnType, Ts... ArgSpecs);
template <typename TLHS, typename TRHS>
BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
template <typename T>
BuiltinTypeMethodBuilder &getResourceHandle(T ResourceRecord);
template <typename TResource, typename TValue>
BuiltinTypeMethodBuilder &setHandleFieldOnResource(TResource ResourceRecord,
TValue HandleValue);
template <typename T> BuiltinTypeMethodBuilder &returnValue(T ReturnValue);
BuiltinTypeDeclBuilder &finalize();
Expr *getResourceHandleExpr();

Expand Down Expand Up @@ -328,19 +352,29 @@ Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) {
}

ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
if (PH >= PlaceHolder::LocalVar_0) {
unsigned Index = static_cast<unsigned>(PH) -
static_cast<unsigned>(PlaceHolder::LocalVar_0);
assert(Index < LocalVars.size() && "local var index out of range");
VarDecl *VD = LocalVars[Index];
return DeclRefExpr::Create(
AST, NestedNameSpecifierLoc(), SourceLocation(), VD, false,
DeclarationNameInfo(VD->getDeclName(), SourceLocation()), VD->getType(),
VK_LValue);
}

ParmVarDecl *ParamDecl = Method->getParamDecl(static_cast<unsigned>(PH));
return DeclRefExpr::Create(
AST, NestedNameSpecifierLoc(), SourceLocation(), ParamDecl, false,
DeclarationNameInfo(ParamDecl->getDeclName(), SourceLocation()),
ParamDecl->getType(), VK_PRValue);
}

BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB,
StringRef NameStr,
QualType ReturnTy,
bool IsConst, bool IsCtor)
BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(
BuiltinTypeDeclBuilder &DB, StringRef NameStr, QualType ReturnTy,
bool IsConst, bool IsCtor, AccessSpecifier Access, StorageClass SC)
: DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst),
IsCtor(IsCtor) {
IsCtor(IsCtor), Access(Access), SC(SC) {

assert((!NameStr.empty() || IsCtor) && "method needs a name");
assert(((IsCtor && !IsConst) || !IsCtor) && "constructor cannot be const");
Expand Down Expand Up @@ -390,10 +424,9 @@ void BuiltinTypeMethodBuilder::createDecl() {
ExplicitSpecifier(), false, true, false,
ConstexprSpecKind::Unspecified);
else
Method =
CXXMethodDecl::Create(AST, DeclBuilder.Record, SourceLocation(),
NameInfo, FuncTy, TSInfo, SC_None, false, false,
ConstexprSpecKind::Unspecified, SourceLocation());
Method = CXXMethodDecl::Create(
AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo, SC,
false, false, ConstexprSpecKind::Unspecified, SourceLocation());

// create params & set them to the function prototype
SmallVector<ParmVarDecl *> ParmDecls;
Expand Down Expand Up @@ -431,15 +464,31 @@ Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() {
OK_Ordinary);
}

BuiltinTypeMethodBuilder &
BuiltinTypeMethodBuilder::createLocalVar(StringRef Name, QualType Ty) {
ensureCompleteDecl();

ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
VarDecl *VD =
VarDecl::Create(AST, Method, SourceLocation(), SourceLocation(),
&AST.Idents.get(Name, tok::TokenKind::identifier), Ty,
AST.getTrivialTypeSourceInfo(Ty), SC_None);
LocalVars.push_back(VD);
DeclStmt *DS = new (AST)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who owns the lifetime of DS? Do we have a general pattern? I'm used to smart pointers galore.

Copy link
Member Author

@hekota hekota Sep 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ASTContext owns all allocations of AST nodes and will take care of freeing the memory.

clang::DeclStmt(DeclGroupRef(VD), SourceLocation(), SourceLocation());
StmtsList.push_back(DS);
return *this;
}

template <typename... Ts>
BuiltinTypeMethodBuilder &
BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
QualType ReturnType, Ts... ArgSpecs) {
ensureCompleteDecl();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this moved up intentionally?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this move was intentional. We need a complete method declaration (=all parameters created) before convertPlaceHolder can refer to them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no need to move this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This move was intentional. We need a complete method declaration (=all parameters created) before convertPlaceHolder can refer to them.


std::array<Expr *, sizeof...(ArgSpecs)> Args{
convertPlaceholder(std::forward<Ts>(ArgSpecs))...};

ensureCompleteDecl();

ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName);
DeclRefExpr *DRE = DeclRefExpr::Create(
Expand Down Expand Up @@ -483,6 +532,55 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) {
return *this;
}

template <typename T>
BuiltinTypeMethodBuilder &
BuiltinTypeMethodBuilder::getResourceHandle(T ResourceRecord) {
ensureCompleteDecl();

Expr *ResourceExpr = convertPlaceholder(ResourceRecord);

ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
MemberExpr *HandleExpr = MemberExpr::CreateImplicit(
AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
OK_Ordinary);
StmtsList.push_back(HandleExpr);
return *this;
}

template <typename TResource, typename TValue>
BuiltinTypeMethodBuilder &
BuiltinTypeMethodBuilder::setHandleFieldOnResource(TResource ResourceRecord,
TValue HandleValue) {
ensureCompleteDecl();

Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
Expr *HandleValueExpr = convertPlaceholder(HandleValue);

ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
MemberExpr *HandleMemberExpr = MemberExpr::CreateImplicit(
AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
OK_Ordinary);
Stmt *AssignStmt = BinaryOperator::Create(
DeclBuilder.SemaRef.getASTContext(), HandleMemberExpr, HandleValueExpr,
BO_Assign, HandleMemberExpr->getType(), ExprValueKind::VK_PRValue,
ExprObjectKind::OK_Ordinary, SourceLocation(), FPOptionsOverride());
StmtsList.push_back(AssignStmt);
return *this;
}

template <typename T>
BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnValue(T ReturnValue) {
ensureCompleteDecl();

Expr *ReturnValueExpr = convertPlaceholder(ReturnValue);
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
StmtsList.push_back(
ReturnStmt::Create(AST, SourceLocation(), ReturnValueExpr, nullptr));
return *this;
}

BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() {
assert(!DeclBuilder.Record->isCompleteDefinition() &&
"record is already complete");
Expand Down Expand Up @@ -510,7 +608,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() {
Method->setBody(CompoundStmt::Create(AST, StmtsList, FPOptionsOverride(),
SourceLocation(), SourceLocation()));
Method->setLexicalDeclContext(DeclBuilder.Record);
Method->setAccess(AccessSpecifier::AS_public);
Method->setAccess(Access);
Method->addAttr(AlwaysInlineAttr::CreateImplicit(
AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
DeclBuilder.Record->addDecl(Method);
Expand Down Expand Up @@ -676,6 +774,58 @@ BuiltinTypeDeclBuilder::addHandleConstructorFromImplicitBinding() {
.finalize();
}

BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromBinding() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: addCreateFromBinding and addCreateFromImplicitBinding are super similar. Do we have a general preference of having explicit functions vs an input argument for this? Just the call to BuiltinTypeMethodBuilder constructor and the first addparam are different.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do want these methods to be separate with different names since Sema and CodeGen will search for them by name. There are also going to be methods for initializing resources from dynamic binding, or resources with separate binding for counter - the complete list of create methods will be more varied.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Alex was trying to say that the implementations of the builder functions are really similar. That is, would it be worth it to abstract out a helper along the lines of

BuiltinTypeDeclBuilder &addStaticResoureConstructor(StringRef Name, StringRef Builtin, ArrayRef<std::pair<StringRef, QualType>> Params);

I think it might clean this up a bit, but I'm also okay with waiting for some of the other initialization functions to come in before settling on the best abstraction here. Up to you.

if (Record->isCompleteDefinition())
return *this;

using PH = BuiltinTypeMethodBuilder::PlaceHolder;
ASTContext &AST = SemaRef.getASTContext();
QualType HandleType = getResourceHandleField()->getType();
QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));

return BuiltinTypeMethodBuilder(*this, "__createFromBinding", RecordType,
false, false, AS_public, SC_Static)
.addParam("registerNo", AST.UnsignedIntTy)
.addParam("spaceNo", AST.UnsignedIntTy)
.addParam("range", AST.IntTy)
.addParam("index", AST.UnsignedIntTy)
.addParam("name", AST.getPointerType(AST.CharTy.withConst()))
.createLocalVar("tmp", RecordType)
.getResourceHandle(PH::LocalVar_0)
.callBuiltin("__builtin_hlsl_resource_handlefrombinding", HandleType,
PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3, PH::_4)
.setHandleFieldOnResource(PH::LocalVar_0, PH::LastStmt)
.returnValue(PH::LocalVar_0)
.finalize();
}

BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromImplicitBinding() {
if (Record->isCompleteDefinition())
return *this;

using PH = BuiltinTypeMethodBuilder::PlaceHolder;
ASTContext &AST = SemaRef.getASTContext();
QualType HandleType = getResourceHandleField()->getType();
QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));

return BuiltinTypeMethodBuilder(*this, "__createFromImplicitBinding",
RecordType, false, false, AS_public,
SC_Static)
.addParam("orderId", AST.UnsignedIntTy)
.addParam("spaceNo", AST.UnsignedIntTy)
.addParam("range", AST.IntTy)
.addParam("index", AST.UnsignedIntTy)
.addParam("name", AST.getPointerType(AST.CharTy.withConst()))
.createLocalVar("tmp", RecordType)
.getResourceHandle(PH::LocalVar_0)
.callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding",
HandleType, PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3,
PH::_4)
.setHandleFieldOnResource(PH::LocalVar_0, PH::LastStmt)
.returnValue(PH::LocalVar_0)
.finalize();
}

BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
ASTContext &AST = Record->getASTContext();
DeclarationName Subscript =
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ class BuiltinTypeDeclBuilder {
BuiltinTypeDeclBuilder &addHandleConstructorFromBinding();
BuiltinTypeDeclBuilder &addHandleConstructorFromImplicitBinding();

// Static create methods
BuiltinTypeDeclBuilder &addCreateFromBinding();
BuiltinTypeDeclBuilder &addCreateFromImplicitBinding();

// Builtin types methods
BuiltinTypeDeclBuilder &addLoadMethods();
BuiltinTypeDeclBuilder &addIncrementCounterMethod();
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
return BuiltinTypeDeclBuilder(S, Decl)
.addHandleMember(RC, IsROV, RawBuffer)
.addDefaultHandleConstructor()
.addCreateFromBinding()
.addCreateFromImplicitBinding()
.addHandleConstructorFromBinding()
.addHandleConstructorFromImplicitBinding();
}
Expand Down
60 changes: 58 additions & 2 deletions clang/test/AST/HLSL/ByteAddressBuffers-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,62 @@ RESOURCE Buffer;
// CHECK-NEXT: CXXThisExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue implicit this
// CHECK-NEXT: AlwaysInlineAttr

// Static __createFromBinding method

// CHECK: CXXMethodDecl {{.*}} __createFromBinding 'hlsl::[[RESOURCE]] (unsigned int, unsigned int, int, unsigned int, const char *)' static
// CHECK-NEXT: ParmVarDecl {{.*}} registerNo 'unsigned int'
// CHECK-NEXT: ParmVarDecl {{.*}} spaceNo 'unsigned int'
// CHECK-NEXT: ParmVarDecl {{.*}} range 'int'
// CHECK-NEXT: ParmVarDecl {{.*}} index 'unsigned int'
// CHECK-NEXT: ParmVarDecl {{.*}} name 'const char *'
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl {{.*}} tmp 'hlsl::[[RESOURCE]]'
// CHECK-NEXT: BinaryOperator {{.*}} '__hlsl_resource_t {{.*}}]]' '='
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t {{.*}}'
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefrombinding' 'void (...) noexcept'
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'registerNo' 'unsigned int'
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'spaceNo' 'unsigned int'
// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} 'range' 'int'
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int'
// CHECK-NEXT: DeclRefExpr {{.*}} 'const char *' ParmVar {{.*}} 'name' 'const char *'
// CHECK-NEXT: ReturnStmt
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline

// Static __createFromImplicitBinding method

// CHECK: CXXMethodDecl {{.*}} __createFromImplicitBinding 'hlsl::[[RESOURCE]] (unsigned int, unsigned int, int, unsigned int, const char *)' static
// CHECK-NEXT: ParmVarDecl {{.*}} orderId 'unsigned int'
// CHECK-NEXT: ParmVarDecl {{.*}} spaceNo 'unsigned int'
// CHECK-NEXT: ParmVarDecl {{.*}} range 'int'
// CHECK-NEXT: ParmVarDecl {{.*}} index 'unsigned int'
// CHECK-NEXT: ParmVarDecl {{.*}} name 'const char *'
// CHECK-NEXT: CompoundStmt {{.*}}
// CHECK-NEXT: DeclStmt {{.*}}
// CHECK-NEXT: VarDecl {{.*}} tmp 'hlsl::[[RESOURCE]]'
// CHECK-NEXT: BinaryOperator {{.*}} '__hlsl_resource_t {{.*}}]]' '='
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
// CHECK-NEXT: CallExpr {{.*}} '__hlsl_resource_t {{.*}}'
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(...) noexcept' <BuiltinFnToFnPtr>
// CHECK-NEXT: DeclRefExpr {{.*}} '<builtin fn type>' Function {{.*}} '__builtin_hlsl_resource_handlefromimplicitbinding' 'void (...) noexcept'
// CHECK-NEXT: MemberExpr {{.*}} '__hlsl_resource_t {{.*}}' lvalue .__handle
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'orderId' 'unsigned int'
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'spaceNo' 'unsigned int'
// CHECK-NEXT: DeclRefExpr {{.*}} 'int' ParmVar {{.*}} 'range' 'int'
// CHECK-NEXT: DeclRefExpr {{.*}} 'unsigned int' ParmVar {{.*}} 'index' 'unsigned int'
// CHECK-NEXT: DeclRefExpr {{.*}} 'const char *' ParmVar {{.*}} 'name' 'const char *'
// CHECK-NEXT: ReturnStmt
// CHECK-NEXT: DeclRefExpr {{.*}} 'hlsl::[[RESOURCE]]' lvalue Var {{.*}} 'tmp' 'hlsl::[[RESOURCE]]'
// CHECK-NEXT: AlwaysInlineAttr {{.*}} Implicit always_inline

// Constructor from binding

// CHECK: CXXConstructorDecl {{.*}} [[RESOURCE]] 'void (unsigned int, unsigned int, int, unsigned int, const char *)' inline
Expand Down Expand Up @@ -104,5 +160,5 @@ RESOURCE Buffer;
// CHECK-NEXT: DeclRefExpr {{.*}} 'const char *' ParmVar {{.*}} 'name' 'const char *'
// CHECK-NEXT: AlwaysInlineAttr

// CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'const element_type &(unsigned int) const'
// CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'element_type &(unsigned int)'
// CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'const char8_t &(unsigned int) const'
// CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl {{.*}} operator[] 'char8_t &(unsigned int)'
Loading