1515#include " clang/AST/Decl.h"
1616#include " clang/AST/DeclBase.h"
1717#include " clang/AST/DeclCXX.h"
18+ #include " clang/AST/DeclarationName.h"
1819#include " clang/AST/DynamicRecursiveASTVisitor.h"
1920#include " clang/AST/Expr.h"
2021#include " clang/AST/Type.h"
4647using namespace clang ;
4748using RegisterType = HLSLResourceBindingAttr::RegisterType;
4849
49- static CXXRecordDecl *createHostLayoutStruct (Sema &S, CXXRecordDecl *StructDecl,
50- HLSLBufferDecl *BufDecl );
50+ static CXXRecordDecl *createHostLayoutStruct (Sema &S,
51+ CXXRecordDecl *StructDecl );
5152
5253static RegisterType getRegisterType (ResourceClass RC) {
5354 switch (RC) {
@@ -268,6 +269,30 @@ static bool isZeroSizedArray(const ConstantArrayType *CAT) {
268269 return CAT != nullptr ;
269270}
270271
272+ // Returns true if the record type is an HLSL resource class
273+ static bool isResourceRecordType (const Type *Ty) {
274+ return HLSLAttributedResourceType::findHandleTypeOnResource (Ty) != nullptr ;
275+ }
276+
277+ // Returns true if the type is a leaf element type that is not valid to be included
278+ // in HLSL Buffer, such as a resource class, empty struct, zero-sized array,
279+ // or a builtin intangible type.
280+ // Returns false it is a valid leaf element type or if it is a record type that
281+ // needs to be inspected further.
282+ static bool isInvalidConstantBufferLeafElementType (const Type *Ty) {
283+ if (Ty->isRecordType ()) {
284+ if (isResourceRecordType (Ty) || Ty->getAsCXXRecordDecl ()->isEmpty ())
285+ return true ;
286+ return false ;
287+ }
288+ if (Ty->isConstantArrayType () &&
289+ isZeroSizedArray (cast<ConstantArrayType>(Ty)))
290+ return true ;
291+ if (Ty->isHLSLBuiltinIntangibleType ())
292+ return true ;
293+ return false ;
294+ }
295+
271296// Returns true if the struct contains at least one element that prevents it
272297// from being included inside HLSL Buffer as is, such as an intangible type,
273298// empty struct, or zero-sized array. If it does, a new implicit layout struct
@@ -279,13 +304,11 @@ static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD) {
279304 // check fields
280305 for (const FieldDecl *Field : RD->fields ()) {
281306 QualType Ty = Field->getType ();
282- if (Ty->isRecordType ()) {
283- if (requiresImplicitBufferLayoutStructure (Ty->getAsCXXRecordDecl ()))
284- return true ;
285- } else if (Ty->isConstantArrayType ()) {
286- if (isZeroSizedArray (cast<ConstantArrayType>(Ty)))
287- return true ;
288- }
307+ if (isInvalidConstantBufferLeafElementType (Ty.getTypePtr ()))
308+ return true ;
309+ if (Ty->isRecordType () &&
310+ requiresImplicitBufferLayoutStructure (Ty->getAsCXXRecordDecl ()))
311+ return true ;
289312 }
290313 // check bases
291314 for (const CXXBaseSpecifier &Base : RD->bases ())
@@ -295,25 +318,28 @@ static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD) {
295318 return false ;
296319}
297320
298- static CXXRecordDecl *findRecordDecl (Sema &S, IdentifierInfo *II,
299- DeclContext *DC) {
300- DeclarationNameInfo NameInfo =
301- DeclarationNameInfo (DeclarationName (II), SourceLocation ());
302- LookupResult R (S, NameInfo, Sema::LookupTagName);
303- S.LookupName (R, S.getScopeForContext (DC));
304- if (R.isSingleResult ())
305- return R.getAsSingle <CXXRecordDecl>();
306- return nullptr ;
321+ static CXXRecordDecl *findRecordDeclInContext (IdentifierInfo *II,
322+ DeclContext *DC) {
323+ CXXRecordDecl *RD = nullptr ;
324+ for (NamedDecl *Decl :
325+ DC->getNonTransparentContext ()->lookup (DeclarationName (II))) {
326+ if (CXXRecordDecl *FoundRD = dyn_cast<CXXRecordDecl>(Decl)) {
327+ assert (RD == nullptr &&
328+ " there should be at most 1 record by a given name in a scope" );
329+ RD = FoundRD;
330+ }
331+ }
332+ return RD;
307333}
308334
309335// Creates a name for buffer layout struct using the provide name base.
310336// If the name must be unique (not previously defined), a suffix is added
311337// until a unique name is found.
312- static IdentifierInfo *getHostLayoutStructName (Sema &S,
313- IdentifierInfo *NameBaseII,
314- bool MustBeUnique,
315- DeclContext *DC) {
338+ static IdentifierInfo *getHostLayoutStructName (Sema &S, NamedDecl *BaseDecl,
339+ bool MustBeUnique) {
316340 ASTContext &AST = S.getASTContext ();
341+
342+ IdentifierInfo *NameBaseII = BaseDecl->getIdentifier ();
317343 StringRef NameBase;
318344 if (NameBaseII) {
319345 NameBase = NameBaseII->getName ();
@@ -333,39 +359,31 @@ static IdentifierInfo *getHostLayoutStructName(Sema &S,
333359 if (suffix != 0 )
334360 II = &AST.Idents .get ((Name + " _" + Twine (suffix)).str (),
335361 tok::TokenKind::identifier);
336- if (!findRecordDecl (S, II, DC ))
362+ if (!findRecordDeclInContext ( II, BaseDecl-> getDeclContext () ))
337363 return II;
338364 // declaration with that name already exists - increment suffix and try
339365 // again until unique name is found
340366 suffix++;
341367 };
342368}
343369
344- // Returns true if the record type is an HLSL resource class
345- static bool isResourceRecordType (const Type *Ty) {
346- return HLSLAttributedResourceType::findHandleTypeOnResource (Ty) != nullptr ;
347- }
348-
349370// Creates a field declaration of given name and type for HLSL buffer layout
350371// struct. Returns nullptr if the type cannot be use in HLSL Buffer layout.
351372static FieldDecl *createFieldForHostLayoutStruct (Sema &S, const Type *Ty,
352373 IdentifierInfo *II,
353- CXXRecordDecl *LayoutStruct,
354- HLSLBufferDecl *BufDecl) {
374+ CXXRecordDecl *LayoutStruct) {
375+ if (isInvalidConstantBufferLeafElementType (Ty))
376+ return nullptr ;
377+
355378 if (Ty->isRecordType ()) {
356- if (isResourceRecordType (Ty))
357- return nullptr ;
358379 CXXRecordDecl *RD = Ty->getAsCXXRecordDecl ();
359380 if (requiresImplicitBufferLayoutStructure (RD)) {
360- RD = createHostLayoutStruct (S, RD, BufDecl );
381+ RD = createHostLayoutStruct (S, RD);
361382 if (!RD)
362383 return nullptr ;
363384 Ty = RD->getTypeForDecl ();
364385 }
365386 }
366- if (Ty->isConstantArrayType () &&
367- isZeroSizedArray (cast<ConstantArrayType>(Ty)))
368- return nullptr ;
369387
370388 QualType QT = QualType (Ty, 0 );
371389 ASTContext &AST = S.getASTContext ();
@@ -384,23 +402,21 @@ static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty,
384402// - empty structs
385403// - zero-sized arrays
386404// Returns nullptr if the resulting layout struct would be empty.
387- static CXXRecordDecl *createHostLayoutStruct (Sema &S, CXXRecordDecl *StructDecl,
388- HLSLBufferDecl *BufDecl ) {
405+ static CXXRecordDecl *createHostLayoutStruct (Sema &S,
406+ CXXRecordDecl *StructDecl ) {
389407 assert (requiresImplicitBufferLayoutStructure (StructDecl) &&
390408 " struct is already HLSL buffer compatible" );
391409
392410 ASTContext &AST = S.getASTContext ();
393411 DeclContext *DC = StructDecl->getDeclContext ();
394- IdentifierInfo *II = getHostLayoutStructName (
395- S, StructDecl->getIdentifier (), false , BufDecl->getDeclContext ());
412+ IdentifierInfo *II = getHostLayoutStructName (S, StructDecl, false );
396413
397414 // reuse existing if the layout struct if it already exists
398- if (CXXRecordDecl *RD = findRecordDecl (S, II, DC))
415+ if (CXXRecordDecl *RD = findRecordDeclInContext ( II, DC))
399416 return RD;
400417
401- CXXRecordDecl *LS =
402- CXXRecordDecl::Create (AST, TagDecl::TagKind::Class, BufDecl,
403- SourceLocation (), SourceLocation (), II);
418+ CXXRecordDecl *LS = CXXRecordDecl::Create (
419+ AST, TagDecl::TagKind::Class, DC, SourceLocation (), SourceLocation (), II);
404420 LS->setImplicit (true );
405421 LS->startDefinition ();
406422
@@ -410,7 +426,7 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl *StructDecl,
410426 CXXBaseSpecifier Base = *StructDecl->bases_begin ();
411427 CXXRecordDecl *BaseDecl = Base.getType ()->getAsCXXRecordDecl ();
412428 if (requiresImplicitBufferLayoutStructure (BaseDecl)) {
413- BaseDecl = createHostLayoutStruct (S, BaseDecl, BufDecl );
429+ BaseDecl = createHostLayoutStruct (S, BaseDecl);
414430 if (BaseDecl) {
415431 TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo (
416432 QualType (BaseDecl->getTypeForDecl (), 0 ));
@@ -427,15 +443,16 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl *StructDecl,
427443 // filter struct fields
428444 for (const FieldDecl *FD : StructDecl->fields ()) {
429445 const Type *Ty = FD->getType ()->getUnqualifiedDesugaredType ();
430- if (FieldDecl *NewFD = createFieldForHostLayoutStruct (
431- S, Ty, FD->getIdentifier (), LS, BufDecl ))
446+ if (FieldDecl *NewFD =
447+ createFieldForHostLayoutStruct ( S, Ty, FD->getIdentifier (), LS))
432448 LS->addDecl (NewFD);
433449 }
434450 LS->completeDefinition ();
435451
436452 if (LS->field_empty () && LS->getNumBases () == 0 )
437453 return nullptr ;
438- BufDecl->addDecl (LS);
454+
455+ DC->addDecl (LS);
439456 return LS;
440457}
441458
@@ -449,8 +466,7 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl *StructDecl,
449466// The layour struct will be added to the HLSLBufferDecl declarations.
450467void createHostLayoutStructForBuffer (Sema &S, HLSLBufferDecl *BufDecl) {
451468 ASTContext &AST = S.getASTContext ();
452- IdentifierInfo *II = getHostLayoutStructName (S, BufDecl->getIdentifier (),
453- true , BufDecl->getDeclContext ());
469+ IdentifierInfo *II = getHostLayoutStructName (S, BufDecl, true );
454470
455471 CXXRecordDecl *LS =
456472 CXXRecordDecl::Create (AST, TagDecl::TagKind::Class, BufDecl,
@@ -463,8 +479,8 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
463479 if (!VD || VD->getStorageClass () == SC_Static)
464480 continue ;
465481 const Type *Ty = VD->getType ()->getUnqualifiedDesugaredType ();
466- if (FieldDecl *FD = createFieldForHostLayoutStruct (
467- S, Ty, VD->getIdentifier (), LS, BufDecl ))
482+ if (FieldDecl *FD =
483+ createFieldForHostLayoutStruct ( S, Ty, VD->getIdentifier (), LS))
468484 LS->addDecl (FD);
469485 }
470486 LS->completeDefinition ();
0 commit comments