diff --git a/clang/include/clang/Sema/HLSLExternalSemaSource.h b/clang/include/clang/Sema/HLSLExternalSemaSource.h --- a/clang/include/clang/Sema/HLSLExternalSemaSource.h +++ b/clang/include/clang/Sema/HLSLExternalSemaSource.h @@ -15,6 +15,7 @@ #include "llvm/ADT/DenseMap.h" #include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/MultiplexExternalSemaSource.h" namespace clang { class NamespaceDecl; @@ -24,6 +25,7 @@ Sema *SemaPtr = nullptr; NamespaceDecl *HLSLNamespace; CXXRecordDecl *ResourceDecl; + ExternalSemaSource *ExternalSema = nullptr; using CompletionFunction = std::function; llvm::DenseMap Completions; @@ -48,6 +50,31 @@ using ExternalASTSource::CompleteType; /// Complete an incomplete HLSL builtin type void CompleteType(TagDecl *Tag) override; + void SetExternalSema(ExternalSemaSource *ExtSema) { ExternalSema = ExtSema; } +}; + +/// Members of ChainedHLSLExternalSemaSource, factored out so we can initialize +/// them before we initialize the ExternalSemaSource base class. +struct ChainedHLSLExternalSemaSourceMembers { + ChainedHLSLExternalSemaSourceMembers(ExternalSemaSource *ExtSema) + : ExternalSema(ExtSema) { + HLSLSema.SetExternalSema(ExtSema); + } + HLSLExternalSemaSource HLSLSema; + IntrusiveRefCntPtr ExternalSema; +}; + +class ChainedHLSLExternalSemaSource + : private ChainedHLSLExternalSemaSourceMembers, + public MultiplexExternalSemaSource { +public: + ChainedHLSLExternalSemaSource(ExternalSemaSource *ExtSema) + : ChainedHLSLExternalSemaSourceMembers(ExtSema), + // NOTE: HLSLSema after ExternalSema so HLSLSema initialize after + // ExternalSema. + // When initialize HLSLSema, reuse hlsl decls if already in + // ExternalSema. + MultiplexExternalSemaSource(*ExternalSema.get(), HLSLSema) {} }; } // namespace clang diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -1018,9 +1018,16 @@ // Setup HLSL External Sema Source if (CI.getLangOpts().HLSL && CI.hasASTContext()) { - IntrusiveRefCntPtr HLSLSema( - new HLSLExternalSemaSource()); - CI.getASTContext().setExternalSource(HLSLSema); + if (auto *SemaSource = dyn_cast_if_present( + CI.getASTContext().getExternalSource())) { + IntrusiveRefCntPtr HLSLSema( + new HLSLExternalSemaSourceChain(SemaSource)); + CI.getASTContext().setExternalSource(HLSLSema); + } else { + IntrusiveRefCntPtr HLSLSema( + new HLSLExternalSemaSource()); + CI.getASTContext().setExternalSource(HLSLSema); + } } FailureCleanup.release(); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -250,9 +250,51 @@ HLSLExternalSemaSource::~HLSLExternalSemaSource() {} +static NamedDecl *findDecl(ASTContext &AST, Sema &S, StringRef Name, + Sema::LookupNameKind Kind) { + IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); + DeclarationNameInfo NameInfo{DeclarationName{&II}, SourceLocation()}; + LookupResult R(S, NameInfo, Kind); + S.LookupName(R, S.getCurScope()); + NamedDecl *D = nullptr; + if (!R.isAmbiguous() && !R.empty()) + D = R.getRepresentativeDecl(); + return D; +} + void HLSLExternalSemaSource::InitializeSema(Sema &S) { SemaPtr = &S; ASTContext &AST = SemaPtr->getASTContext(); + + if (ExternalSema) { + NamespaceDecl *ExternlHLSL = llvm::dyn_cast_if_present( + findDecl(AST, S, "hlsl", Sema::LookupNameKind::LookupNamespaceName)); + // Try to initailize from ExternalSema. + if (ExternlHLSL) { + auto *Resource = llvm::dyn_cast_if_present( + findDecl(AST, S, "Resource", Sema::LookupNameKind::LookupOrdinaryName)); + + auto *RWBuffer = llvm::dyn_cast_if_present( + findDecl(AST, S, "RWBuffer", Sema::LookupNameKind::LookupAnyName)); + + // Find all things from ExternalSema, use them and return. + if (Resource && RWBuffer) { + HLSLNamespace = ExternlHLSL; + ResourceDecl = Resource; + CXXRecordDecl *Decl = RWBuffer->getTemplatedDecl(); + if (!Decl->hasDefinition()) { + // Mark ExternalLexicalStorage so complete type will be called for + // ExternalAST path. + Decl->setHasExternalLexicalStorage(); + Completions.insert(std::make_pair( + Decl, std::bind(&HLSLExternalSemaSource::completeBufferType, this, + std::placeholders::_1))); + } + return; + } + } + } + IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier); HLSLNamespace = NamespaceDecl::Create(AST, AST.getTranslationUnitDecl(), false, diff --git a/clang/test/AST/HLSL/Inputs/pch.hlsl b/clang/test/AST/HLSL/Inputs/pch.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/AST/HLSL/Inputs/pch.hlsl @@ -0,0 +1,4 @@ + +float2 foo(float2 a, float2 b) { + return a + b; +} diff --git a/clang/test/AST/HLSL/pch.hlsl b/clang/test/AST/HLSL/pch.hlsl new file mode 100644 --- /dev/null +++ b/clang/test/AST/HLSL/pch.hlsl @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl \ +// RUN: -finclude-default-header -emit-pch -o %t %S/Inputs/pch.hlsl +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl \ +// RUN: -finclude-default-header -include-pch %t -fsyntax-only -ast-dump-all %s \ +// RUN: | FileCheck %s + +// Make sure PCH works by using function declared in PCH header and declare a RWBuffer in current file. +// CHECK:FunctionDecl 0x[[FOO:[0-9a-f]+]] <{{.*}}:2:1, line:4:1> line:2:8 imported used foo 'float2 (float2, float2)' +// CHECK:VarDecl 0x{{[0-9a-f]+}} <{{.*}}:10:1, col:23> col:23 Buffer 'hlsl::RWBuffer':'hlsl::RWBuffer<>' +hlsl::RWBuffer Buffer; + +float2 bar(float2 a, float2 b) { +// CHECK:CallExpr 0x{{[0-9a-f]+}} 'float2':'float __attribute__((ext_vector_type(2)))' +// CHECK-NEXT:ImplicitCastExpr 0x{{[0-9a-f]+}} 'float2 (*)(float2, float2)' +// CHECK-NEXT:`-DeclRefExpr 0x{{[0-9a-f]+}} 'float2 (float2, float2)' lvalue Function 0x[[FOO]] 'foo' 'float2 (float2, float2)' + return foo(a, b); +}