@@ -4491,10 +4491,22 @@ SYCLIntegrationHeader::SYCLIntegrationHeader(bool _UnnamedLambdaSupport,
4491
4491
: UnnamedLambdaSupport(_UnnamedLambdaSupport), S(_S) {}
4492
4492
4493
4493
void SYCLIntegrationFooter::addVarDecl (const VarDecl *VD) {
4494
+ // Skip the dependent version of these variables, we only care about them
4495
+ // after instantiation.
4496
+ if (VD->getDeclContext ()->isDependentContext ())
4497
+ return ;
4494
4498
// Step 1: ensure that this is of the correct type-spec-constant template
4495
4499
// specialization).
4496
- if (!Util::isSyclSpecIdType (VD->getType ()))
4497
- return ;
4500
+ if (!Util::isSyclSpecIdType (VD->getType ())) {
4501
+ // Handle the case where this could be a deduced type, such as a deduction
4502
+ // guide. We have to do this here since this function, unlike most of the
4503
+ // rest of this file, is called during Sema instead of after it. We will
4504
+ // also have to filter out after deduction later.
4505
+ QualType Ty = VD->getType ().getCanonicalType ();
4506
+
4507
+ if (!Ty->isUndeducedType ())
4508
+ return ;
4509
+ }
4498
4510
// Step 2: ensure that this is a static member, or a namespace-scope.
4499
4511
// Note that isLocalVarDeclorParm excludes thread-local and static-local
4500
4512
// intentionally, as there is no way to 'spell' one of those in the
@@ -4536,26 +4548,162 @@ void SYCLIntegrationFooter::emitSpecIDName(raw_ostream &O, const VarDecl *VD) {
4536
4548
O << " " ;
4537
4549
}
4538
4550
4539
- bool SYCLIntegrationFooter::emit (raw_ostream &O) {
4551
+ template <typename BeforeFn, typename AfterFn>
4552
+ static void PrintNSHelper (BeforeFn Before, AfterFn After, raw_ostream &OS,
4553
+ const DeclContext *DC) {
4554
+ if (DC->isTranslationUnit ())
4555
+ return ;
4556
+
4557
+ const auto *CurDecl = cast<Decl>(DC);
4558
+ // Ensure we are in the canonical version, so that we know we have the 'full'
4559
+ // name of the thing.
4560
+ CurDecl = CurDecl->getCanonicalDecl ();
4561
+
4562
+ // We are intentionally skipping linkage decls and record decls. Namespaces
4563
+ // can appear in a linkage decl, but not a record decl, so we don't have to
4564
+ // worry about the names getting messed up from that. We handle record decls
4565
+ // later when printing the name of the thing.
4566
+ const auto *NS = dyn_cast<NamespaceDecl>(CurDecl);
4567
+ if (NS)
4568
+ Before (OS, NS);
4569
+
4570
+ if (const DeclContext *NewDC = CurDecl->getDeclContext ())
4571
+ PrintNSHelper (Before, After, OS, NewDC);
4572
+
4573
+ if (NS)
4574
+ After (OS, NS);
4575
+ }
4576
+
4577
+ static void PrintNamespaces (raw_ostream &OS, const DeclContext *DC) {
4578
+ PrintNSHelper ([](raw_ostream &OS, const NamespaceDecl *NS) {},
4579
+ [](raw_ostream &OS, const NamespaceDecl *NS) {
4580
+ if (NS->isInline ())
4581
+ OS << " inline " ;
4582
+ OS << " namespace " ;
4583
+ if (!NS->isAnonymousNamespace ())
4584
+ OS << NS->getName () << " " ;
4585
+ OS << " {\n " ;
4586
+ },
4587
+ OS, DC);
4588
+ }
4589
+
4590
+ static void PrintNSClosingBraces (raw_ostream &OS, const DeclContext *DC) {
4591
+ PrintNSHelper (
4592
+ [](raw_ostream &OS, const NamespaceDecl *NS) {
4593
+ OS << " } // " ;
4594
+ if (NS->isInline ())
4595
+ OS << " inline " ;
4596
+
4597
+ OS << " namespace " ;
4598
+ if (!NS->isAnonymousNamespace ())
4599
+ OS << NS->getName ();
4600
+
4601
+ OS << ' \n ' ;
4602
+ },
4603
+ [](raw_ostream &OS, const NamespaceDecl *NS) {}, OS, DC);
4604
+ }
4605
+
4606
+ static std::string EmitSpecIdShim (raw_ostream &OS, unsigned &ShimCounter,
4607
+ const std::string &LastShim,
4608
+ const NamespaceDecl *AnonNS) {
4609
+ std::string NewShimName =
4610
+ " __sycl_detail::__spec_id_shim_" + std::to_string (ShimCounter) + " ()" ;
4611
+ // Print opening-namespace
4612
+ PrintNamespaces (OS, Decl::castToDeclContext (AnonNS));
4613
+ OS << " namespace __sycl_detail {\n " ;
4614
+ OS << " static constexpr decltype(" << LastShim << " ) &__spec_id_shim_"
4615
+ << ShimCounter << " () {\n " ;
4616
+ OS << " return " << LastShim << " ;\n " ;
4617
+ OS << " }\n " ;
4618
+ OS << " } // namespace __sycl_detail \n " ;
4619
+ PrintNSClosingBraces (OS, Decl::castToDeclContext (AnonNS));
4620
+
4621
+ ++ShimCounter;
4622
+ return std::move (NewShimName);
4623
+ }
4624
+
4625
+ // Emit the list of shims required for a DeclContext, calls itself recursively.
4626
+ static void EmitSpecIdShims (raw_ostream &OS, unsigned &ShimCounter,
4627
+ const DeclContext *DC,
4628
+ std::string &NameForLastShim) {
4629
+ if (DC->isTranslationUnit ()) {
4630
+ NameForLastShim = " ::" + NameForLastShim;
4631
+ return ;
4632
+ }
4633
+
4634
+ const auto *CurDecl = cast<Decl>(DC)->getCanonicalDecl ();
4635
+
4636
+ // We skip linkage decls, since they don't modify the Qualified name.
4637
+ if (const auto *RD = dyn_cast<RecordDecl>(CurDecl)) {
4638
+ NameForLastShim = RD->getNameAsString () + " ::" + NameForLastShim;
4639
+ } else if (const auto *ND = dyn_cast<NamespaceDecl>(CurDecl)) {
4640
+ if (ND->isAnonymousNamespace ()) {
4641
+ // Print current shim, reset 'name for last shim'.
4642
+ NameForLastShim = EmitSpecIdShim (OS, ShimCounter, NameForLastShim, ND);
4643
+ } else {
4644
+ NameForLastShim = ND->getNameAsString () + " ::" + NameForLastShim;
4645
+ }
4646
+ } else {
4647
+ // FIXME: I don't believe there are other declarations that these variables
4648
+ // could possibly find themselves in. LinkageDecls don't change the
4649
+ // qualified name, so there is nothing to do here. At one point we should
4650
+ // probably convince ourselves that this is entire list and remove this
4651
+ // comment.
4652
+ assert ((isa<LinkageSpecDecl, ExternCContextDecl>(CurDecl)) &&
4653
+ " Unhandled decl type" );
4654
+ }
4655
+
4656
+ EmitSpecIdShims (OS, ShimCounter, CurDecl->getDeclContext (), NameForLastShim);
4657
+ }
4658
+
4659
+ // Emit the list of shims required for a variable declaration.
4660
+ // Returns a string containing the FQN of the 'top most' shim, including its
4661
+ // function call parameters.
4662
+ static std::string EmitSpecIdShims (raw_ostream &OS, unsigned &ShimCounter,
4663
+ const VarDecl *VD) {
4664
+ assert (VD->isInAnonymousNamespace () &&
4665
+ " Function assumes this is in an anonymous namespace" );
4666
+ std::string RelativeName = VD->getNameAsString ();
4667
+ EmitSpecIdShims (OS, ShimCounter, VD->getDeclContext (), RelativeName);
4668
+ return std::move (RelativeName);
4669
+ }
4670
+
4671
+ bool SYCLIntegrationFooter::emit (raw_ostream &OS) {
4540
4672
PrintingPolicy Policy{S.getLangOpts ()};
4541
4673
Policy.adjustForCPlusPlusFwdDecl ();
4542
4674
Policy.SuppressTypedefs = true ;
4543
4675
Policy.SuppressUnwrittenScope = true ;
4544
4676
4545
- for (const VarDecl *D : SpecConstants) {
4546
- O << " template<>\n " ;
4547
- O << " inline const char *get_spec_constant_symbolic_ID<" ;
4548
- // Emit the FQN for this, but we probably need to do some funny-business for
4549
- // anonymous namespaces.
4550
- D->printQualifiedName (O, Policy);
4551
- O << " >() {\n " ;
4552
- O << " return \" " ;
4553
- emitSpecIDName (O, D);
4554
- O << " \" ;\n " ;
4555
- O << " }\n " ;
4677
+ // Used to uniquely name the 'shim's as we generate the names in each
4678
+ // anonymous namespace.
4679
+ unsigned ShimCounter = 0 ;
4680
+ for (const VarDecl *VD : SpecConstants) {
4681
+ VD = VD->getCanonicalDecl ();
4682
+ if (VD->isInAnonymousNamespace ()) {
4683
+ std::string TopShim = EmitSpecIdShims (OS, ShimCounter, VD);
4684
+ OS << " namespace sycl {\n " ;
4685
+ OS << " namespace detail {\n " ;
4686
+ OS << " template<>\n " ;
4687
+ OS << " inline const char *get_spec_constant_symbolic_ID<" << TopShim
4688
+ << " >() {\n " ;
4689
+ OS << " return " << TopShim << " ;\n " ;
4690
+ } else {
4691
+ OS << " namespace sycl {\n " ;
4692
+ OS << " namespace detail {\n " ;
4693
+ OS << " template<>\n " ;
4694
+ OS << " inline const char *get_spec_constant_symbolic_ID<::" ;
4695
+ VD->printQualifiedName (OS, Policy);
4696
+ OS << " >() {\n " ;
4697
+ OS << " return \" " ;
4698
+ emitSpecIDName (OS, VD);
4699
+ OS << " \" ;\n " ;
4700
+ }
4701
+ OS << " }\n " ;
4702
+ OS << " } // namespace detail\n " ;
4703
+ OS << " } // namespace sycl\n " ;
4556
4704
}
4557
4705
4558
- O << " #include <CL/sycl/detail/spec_const_integration.hpp>\n " ;
4706
+ OS << " #include <CL/sycl/detail/spec_const_integration.hpp>\n " ;
4559
4707
return true ;
4560
4708
}
4561
4709
0 commit comments