Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/Sema/HLSLExternalSemaSource.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
//
10
//===----------------------------------------------------------------------===//
11
12
#include "clang/Sema/HLSLExternalSemaSource.h"
13
#include "clang/AST/ASTContext.h"
14
#include "clang/AST/Attr.h"
15
#include "clang/AST/DeclCXX.h"
16
#include "clang/Basic/AttrKinds.h"
17
#include "clang/Basic/HLSLRuntime.h"
18
#include "clang/Sema/Lookup.h"
19
#include "clang/Sema/Sema.h"
20
#include "llvm/Frontend/HLSL/HLSLResource.h"
21
22
#include <functional>
23
24
using namespace clang;
25
using namespace llvm::hlsl;
26
27
namespace {
28
29
struct TemplateParameterListBuilder;
30
31
struct BuiltinTypeDeclBuilder {
32
  CXXRecordDecl *Record = nullptr;
33
  ClassTemplateDecl *Template = nullptr;
34
  ClassTemplateDecl *PrevTemplate = nullptr;
35
  NamespaceDecl *HLSLNamespace = nullptr;
36
  llvm::StringMap<FieldDecl *> Fields;
37
38
0
  BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) {
39
0
    Record->startDefinition();
40
0
    Template = Record->getDescribedClassTemplate();
41
0
  }
42
43
  BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name)
44
0
      : HLSLNamespace(Namespace) {
45
0
    ASTContext &AST = S.getASTContext();
46
0
    IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
47
48
0
    LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
49
0
    CXXRecordDecl *PrevDecl = nullptr;
50
0
    if (S.LookupQualifiedName(Result, HLSLNamespace)) {
51
0
      NamedDecl *Found = Result.getFoundDecl();
52
0
      if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
53
0
        PrevDecl = TD->getTemplatedDecl();
54
0
        PrevTemplate = TD;
55
0
      } else
56
0
        PrevDecl = dyn_cast<CXXRecordDecl>(Found);
57
0
      assert(PrevDecl && "Unexpected lookup result type.");
58
0
    }
59
60
0
    if (PrevDecl && PrevDecl->isCompleteDefinition()) {
61
0
      Record = PrevDecl;
62
0
      return;
63
0
    }
64
65
0
    Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,
66
0
                                   SourceLocation(), SourceLocation(), &II,
67
0
                                   PrevDecl, true);
68
0
    Record->setImplicit(true);
69
0
    Record->setLexicalDeclContext(HLSLNamespace);
70
0
    Record->setHasExternalLexicalStorage();
71
72
    // Don't let anyone derive from built-in types.
73
0
    Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
74
0
                                              FinalAttr::Keyword_final));
75
0
  }
76
77
0
  ~BuiltinTypeDeclBuilder() {
78
0
    if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
79
0
      HLSLNamespace->addDecl(Record);
80
0
  }
81
82
  BuiltinTypeDeclBuilder &
83
  addMemberVariable(StringRef Name, QualType Type,
84
0
                    AccessSpecifier Access = AccessSpecifier::AS_private) {
85
0
    if (Record->isCompleteDefinition())
86
0
      return *this;
87
0
    assert(Record->isBeingDefined() &&
88
0
           "Definition must be started before adding members!");
89
0
    ASTContext &AST = Record->getASTContext();
90
91
0
    IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
92
0
    TypeSourceInfo *MemTySource =
93
0
        AST.getTrivialTypeSourceInfo(Type, SourceLocation());
94
0
    auto *Field = FieldDecl::Create(
95
0
        AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
96
0
        nullptr, false, InClassInitStyle::ICIS_NoInit);
97
0
    Field->setAccess(Access);
98
0
    Field->setImplicit(true);
99
0
    Record->addDecl(Field);
100
0
    Fields[Name] = Field;
101
0
    return *this;
102
0
  }
103
104
  BuiltinTypeDeclBuilder &
105
0
  addHandleMember(AccessSpecifier Access = AccessSpecifier::AS_private) {
106
0
    if (Record->isCompleteDefinition())
107
0
      return *this;
108
0
    QualType Ty = Record->getASTContext().VoidPtrTy;
109
0
    if (Template) {
110
0
      if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
111
0
              Template->getTemplateParameters()->getParam(0)))
112
0
        Ty = Record->getASTContext().getPointerType(
113
0
            QualType(TTD->getTypeForDecl(), 0));
114
0
    }
115
0
    return addMemberVariable("h", Ty, Access);
116
0
  }
117
118
  BuiltinTypeDeclBuilder &annotateResourceClass(ResourceClass RC,
119
0
                                                ResourceKind RK, bool IsROV) {
120
0
    if (Record->isCompleteDefinition())
121
0
      return *this;
122
0
    Record->addAttr(HLSLResourceAttr::CreateImplicit(Record->getASTContext(),
123
0
                                                     RC, RK, IsROV));
124
0
    return *this;
125
0
  }
126
127
  static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
128
0
                                            StringRef Name) {
129
0
    CXXScopeSpec SS;
130
0
    IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
131
0
    DeclarationNameInfo NameInfo =
132
0
        DeclarationNameInfo(DeclarationName(&II), SourceLocation());
133
0
    LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
134
0
    S.LookupParsedName(R, S.getCurScope(), &SS, false);
135
0
    assert(R.isSingleResult() &&
136
0
           "Since this is a builtin it should always resolve!");
137
0
    auto *VD = cast<ValueDecl>(R.getFoundDecl());
138
0
    QualType Ty = VD->getType();
139
0
    return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(),
140
0
                               VD, false, NameInfo, Ty, VK_PRValue);
141
0
  }
142
143
0
  static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) {
144
0
    return IntegerLiteral::Create(
145
0
        AST,
146
0
        llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy),
147
0
                    static_cast<uint8_t>(RC)),
148
0
        AST.UnsignedCharTy, SourceLocation());
149
0
  }
150
151
  BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S,
152
0
                                                      ResourceClass RC) {
153
0
    if (Record->isCompleteDefinition())
154
0
      return *this;
155
0
    ASTContext &AST = Record->getASTContext();
156
157
0
    QualType ConstructorType =
158
0
        AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
159
160
0
    CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
161
0
    DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
162
0
    CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
163
0
        AST, Record, SourceLocation(),
164
0
        DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
165
0
        AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
166
0
        ExplicitSpecifier(), false, true, false,
167
0
        ConstexprSpecKind::Unspecified);
168
169
0
    DeclRefExpr *Fn =
170
0
        lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle");
171
172
0
    Expr *RCExpr = emitResourceClassExpr(AST, RC);
173
0
    Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue,
174
0
                                  SourceLocation(), FPOptionsOverride());
175
176
0
    CXXThisExpr *This = CXXThisExpr::Create(
177
0
        AST, SourceLocation(), Constructor->getFunctionObjectParameterType(),
178
0
        true);
179
0
    Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"],
180
0
                                              Fields["h"]->getType(), VK_LValue,
181
0
                                              OK_Ordinary);
182
183
    // If the handle isn't a void pointer, cast the builtin result to the
184
    // correct type.
185
0
    if (Handle->getType().getCanonicalType() != AST.VoidPtrTy) {
186
0
      Call = CXXStaticCastExpr::Create(
187
0
          AST, Handle->getType(), VK_PRValue, CK_Dependent, Call, nullptr,
188
0
          AST.getTrivialTypeSourceInfo(Handle->getType(), SourceLocation()),
189
0
          FPOptionsOverride(), SourceLocation(), SourceLocation(),
190
0
          SourceRange());
191
0
    }
192
193
0
    BinaryOperator *Assign = BinaryOperator::Create(
194
0
        AST, Handle, Call, BO_Assign, Handle->getType(), VK_LValue, OK_Ordinary,
195
0
        SourceLocation(), FPOptionsOverride());
196
197
0
    Constructor->setBody(
198
0
        CompoundStmt::Create(AST, {Assign}, FPOptionsOverride(),
199
0
                             SourceLocation(), SourceLocation()));
200
0
    Constructor->setAccess(AccessSpecifier::AS_public);
201
0
    Record->addDecl(Constructor);
202
0
    return *this;
203
0
  }
204
205
0
  BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
206
0
    if (Record->isCompleteDefinition())
207
0
      return *this;
208
0
    addArraySubscriptOperator(true);
209
0
    addArraySubscriptOperator(false);
210
0
    return *this;
211
0
  }
212
213
0
  BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
214
0
    if (Record->isCompleteDefinition())
215
0
      return *this;
216
0
    assert(Fields.count("h") > 0 &&
217
0
           "Subscript operator must be added after the handle.");
218
219
0
    FieldDecl *Handle = Fields["h"];
220
0
    ASTContext &AST = Record->getASTContext();
221
222
0
    assert(Handle->getType().getCanonicalType() != AST.VoidPtrTy &&
223
0
           "Not yet supported for void pointer handles.");
224
225
0
    QualType ElemTy =
226
0
        QualType(Handle->getType()->getPointeeOrArrayElementType(), 0);
227
0
    QualType ReturnTy = ElemTy;
228
229
0
    FunctionProtoType::ExtProtoInfo ExtInfo;
230
231
    // Subscript operators return references to elements, const makes the
232
    // reference and method const so that the underlying data is not mutable.
233
0
    ReturnTy = AST.getLValueReferenceType(ReturnTy);
234
0
    if (IsConst) {
235
0
      ExtInfo.TypeQuals.addConst();
236
0
      ReturnTy.addConst();
237
0
    }
238
239
0
    QualType MethodTy =
240
0
        AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
241
0
    auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
242
0
    auto *MethodDecl = CXXMethodDecl::Create(
243
0
        AST, Record, SourceLocation(),
244
0
        DeclarationNameInfo(
245
0
            AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
246
0
            SourceLocation()),
247
0
        MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
248
0
        SourceLocation());
249
250
0
    IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
251
0
    auto *IdxParam = ParmVarDecl::Create(
252
0
        AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
253
0
        &II, AST.UnsignedIntTy,
254
0
        AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
255
0
        SC_None, nullptr);
256
0
    MethodDecl->setParams({IdxParam});
257
258
    // Also add the parameter to the function prototype.
259
0
    auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
260
0
    FnProtoLoc.setParam(0, IdxParam);
261
262
0
    auto *This =
263
0
        CXXThisExpr::Create(AST, SourceLocation(),
264
0
                            MethodDecl->getFunctionObjectParameterType(), true);
265
0
    auto *HandleAccess = MemberExpr::CreateImplicit(
266
0
        AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary);
267
268
0
    auto *IndexExpr = DeclRefExpr::Create(
269
0
        AST, NestedNameSpecifierLoc(), SourceLocation(), IdxParam, false,
270
0
        DeclarationNameInfo(IdxParam->getDeclName(), SourceLocation()),
271
0
        AST.UnsignedIntTy, VK_PRValue);
272
273
0
    auto *Array =
274
0
        new (AST) ArraySubscriptExpr(HandleAccess, IndexExpr, ElemTy, VK_LValue,
275
0
                                     OK_Ordinary, SourceLocation());
276
277
0
    auto *Return = ReturnStmt::Create(AST, SourceLocation(), Array, nullptr);
278
279
0
    MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
280
0
                                             SourceLocation(),
281
0
                                             SourceLocation()));
282
0
    MethodDecl->setLexicalDeclContext(Record);
283
0
    MethodDecl->setAccess(AccessSpecifier::AS_public);
284
0
    MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
285
0
        AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
286
0
    Record->addDecl(MethodDecl);
287
288
0
    return *this;
289
0
  }
290
291
0
  BuiltinTypeDeclBuilder &startDefinition() {
292
0
    if (Record->isCompleteDefinition())
293
0
      return *this;
294
0
    Record->startDefinition();
295
0
    return *this;
296
0
  }
297
298
0
  BuiltinTypeDeclBuilder &completeDefinition() {
299
0
    if (Record->isCompleteDefinition())
300
0
      return *this;
301
0
    assert(Record->isBeingDefined() &&
302
0
           "Definition must be started before completing it.");
303
304
0
    Record->completeDefinition();
305
0
    return *this;
306
0
  }
307
308
  TemplateParameterListBuilder addTemplateArgumentList();
309
  BuiltinTypeDeclBuilder &addSimpleTemplateParams(ArrayRef<StringRef> Names);
310
};
311
312
struct TemplateParameterListBuilder {
313
  BuiltinTypeDeclBuilder &Builder;
314
  ASTContext &AST;
315
  llvm::SmallVector<NamedDecl *> Params;
316
317
  TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB)
318
0
      : Builder(RB), AST(RB.Record->getASTContext()) {}
319
320
0
  ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
321
322
  TemplateParameterListBuilder &
323
0
  addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
324
0
    if (Builder.Record->isCompleteDefinition())
325
0
      return *this;
326
0
    unsigned Position = static_cast<unsigned>(Params.size());
327
0
    auto *Decl = TemplateTypeParmDecl::Create(
328
0
        AST, Builder.Record->getDeclContext(), SourceLocation(),
329
0
        SourceLocation(), /* TemplateDepth */ 0, Position,
330
0
        &AST.Idents.get(Name, tok::TokenKind::identifier), /* Typename */ false,
331
0
        /* ParameterPack */ false);
332
0
    if (!DefaultValue.isNull())
333
0
      Decl->setDefaultArgument(AST.getTrivialTypeSourceInfo(DefaultValue));
334
335
0
    Params.emplace_back(Decl);
336
0
    return *this;
337
0
  }
338
339
0
  BuiltinTypeDeclBuilder &finalizeTemplateArgs() {
340
0
    if (Params.empty())
341
0
      return Builder;
342
0
    auto *ParamList =
343
0
        TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
344
0
                                      Params, SourceLocation(), nullptr);
345
0
    Builder.Template = ClassTemplateDecl::Create(
346
0
        AST, Builder.Record->getDeclContext(), SourceLocation(),
347
0
        DeclarationName(Builder.Record->getIdentifier()), ParamList,
348
0
        Builder.Record);
349
0
    Builder.Record->setDescribedClassTemplate(Builder.Template);
350
0
    Builder.Template->setImplicit(true);
351
0
    Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
352
    // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
353
    // make visible.
354
0
    Builder.Template->setPreviousDecl(Builder.PrevTemplate);
355
0
    Builder.Record->getDeclContext()->addDecl(Builder.Template);
356
0
    Params.clear();
357
358
0
    QualType T = Builder.Template->getInjectedClassNameSpecialization();
359
0
    T = AST.getInjectedClassNameType(Builder.Record, T);
360
361
0
    return Builder;
362
0
  }
363
};
364
} // namespace
365
366
0
TemplateParameterListBuilder BuiltinTypeDeclBuilder::addTemplateArgumentList() {
367
0
  return TemplateParameterListBuilder(*this);
368
0
}
369
370
BuiltinTypeDeclBuilder &
371
0
BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names) {
372
0
  TemplateParameterListBuilder Builder = this->addTemplateArgumentList();
373
0
  for (StringRef Name : Names)
374
0
    Builder.addTypeParameter(Name);
375
0
  return Builder.finalizeTemplateArgs();
376
0
}
377
378
0
HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
379
380
0
void HLSLExternalSemaSource::InitializeSema(Sema &S) {
381
0
  SemaPtr = &S;
382
0
  ASTContext &AST = SemaPtr->getASTContext();
383
  // If the translation unit has external storage force external decls to load.
384
0
  if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
385
0
    (void)AST.getTranslationUnitDecl()->decls_begin();
386
387
0
  IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
388
0
  LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
389
0
  NamespaceDecl *PrevDecl = nullptr;
390
0
  if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
391
0
    PrevDecl = Result.getAsSingle<NamespaceDecl>();
392
0
  HLSLNamespace = NamespaceDecl::Create(
393
0
      AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
394
0
      SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
395
0
  HLSLNamespace->setImplicit(true);
396
0
  HLSLNamespace->setHasExternalLexicalStorage();
397
0
  AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
398
399
  // Force external decls in the HLSL namespace to load from the PCH.
400
0
  (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
401
0
  defineTrivialHLSLTypes();
402
0
  defineHLSLTypesWithForwardDeclarations();
403
404
  // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
405
  // built in types inside a namespace, but we are planning to change that in
406
  // the near future. In order to be source compatible older versions of HLSL
407
  // will need to implicitly use the hlsl namespace. For now in clang everything
408
  // will get added to the namespace, and we can remove the using directive for
409
  // future language versions to match HLSL's evolution.
410
0
  auto *UsingDecl = UsingDirectiveDecl::Create(
411
0
      AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
412
0
      NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
413
0
      AST.getTranslationUnitDecl());
414
415
0
  AST.getTranslationUnitDecl()->addDecl(UsingDecl);
416
0
}
417
418
0
void HLSLExternalSemaSource::defineHLSLVectorAlias() {
419
0
  ASTContext &AST = SemaPtr->getASTContext();
420
421
0
  llvm::SmallVector<NamedDecl *> TemplateParams;
422
423
0
  auto *TypeParam = TemplateTypeParmDecl::Create(
424
0
      AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
425
0
      &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
426
0
  TypeParam->setDefaultArgument(AST.getTrivialTypeSourceInfo(AST.FloatTy));
427
428
0
  TemplateParams.emplace_back(TypeParam);
429
430
0
  auto *SizeParam = NonTypeTemplateParmDecl::Create(
431
0
      AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
432
0
      &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
433
0
      false, AST.getTrivialTypeSourceInfo(AST.IntTy));
434
0
  Expr *LiteralExpr =
435
0
      IntegerLiteral::Create(AST, llvm::APInt(AST.getIntWidth(AST.IntTy), 4),
436
0
                             AST.IntTy, SourceLocation());
437
0
  SizeParam->setDefaultArgument(LiteralExpr);
438
0
  TemplateParams.emplace_back(SizeParam);
439
440
0
  auto *ParamList =
441
0
      TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
442
0
                                    TemplateParams, SourceLocation(), nullptr);
443
444
0
  IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
445
446
0
  QualType AliasType = AST.getDependentSizedExtVectorType(
447
0
      AST.getTemplateTypeParmType(0, 0, false, TypeParam),
448
0
      DeclRefExpr::Create(
449
0
          AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
450
0
          DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
451
0
          AST.IntTy, VK_LValue),
452
0
      SourceLocation());
453
454
0
  auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
455
0
                                       SourceLocation(), &II,
456
0
                                       AST.getTrivialTypeSourceInfo(AliasType));
457
0
  Record->setImplicit(true);
458
459
0
  auto *Template =
460
0
      TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
461
0
                                    Record->getIdentifier(), ParamList, Record);
462
463
0
  Record->setDescribedAliasTemplate(Template);
464
0
  Template->setImplicit(true);
465
0
  Template->setLexicalDeclContext(Record->getDeclContext());
466
0
  HLSLNamespace->addDecl(Template);
467
0
}
468
469
0
void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
470
0
  defineHLSLVectorAlias();
471
472
0
  ResourceDecl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Resource")
473
0
                     .startDefinition()
474
0
                     .addHandleMember(AccessSpecifier::AS_public)
475
0
                     .completeDefinition()
476
0
                     .Record;
477
0
}
478
479
/// Set up common members and attributes for buffer types
480
static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
481
                                              ResourceClass RC, ResourceKind RK,
482
0
                                              bool IsROV) {
483
0
  return BuiltinTypeDeclBuilder(Decl)
484
0
      .addHandleMember()
485
0
      .addDefaultHandleConstructor(S, RC)
486
0
      .annotateResourceClass(RC, RK, IsROV);
487
0
}
488
489
0
void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
490
0
  CXXRecordDecl *Decl;
491
0
  Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
492
0
             .addSimpleTemplateParams({"element_type"})
493
0
             .Record;
494
0
  onCompletion(Decl, [this](CXXRecordDecl *Decl) {
495
0
    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
496
0
                    ResourceKind::TypedBuffer, /*IsROV=*/false)
497
0
        .addArraySubscriptOperators()
498
0
        .completeDefinition();
499
0
  });
500
501
0
  Decl =
502
0
      BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
503
0
          .addSimpleTemplateParams({"element_type"})
504
0
          .Record;
505
0
  onCompletion(Decl, [this](CXXRecordDecl *Decl) {
506
0
    setupBufferType(Decl, *SemaPtr, ResourceClass::UAV,
507
0
                    ResourceKind::TypedBuffer, /*IsROV=*/true)
508
0
        .addArraySubscriptOperators()
509
0
        .completeDefinition();
510
0
  });
511
0
}
512
513
void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
514
0
                                          CompletionFunction Fn) {
515
0
  Completions.insert(std::make_pair(Record->getCanonicalDecl(), Fn));
516
0
}
517
518
0
void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
519
0
  if (!isa<CXXRecordDecl>(Tag))
520
0
    return;
521
0
  auto Record = cast<CXXRecordDecl>(Tag);
522
523
  // If this is a specialization, we need to get the underlying templated
524
  // declaration and complete that.
525
0
  if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
526
0
    Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
527
0
  Record = Record->getCanonicalDecl();
528
0
  auto It = Completions.find(Record);
529
0
  if (It == Completions.end())
530
0
    return;
531
0
  It->second(Record);
532
0
}