1//=- ClangBuiltinsEmitter.cpp - Generate Clang builtin templates-*- C++ -*-===//
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// This tablegen backend emits Clang's builtin templates.
10//
11//===----------------------------------------------------------------------===//
12
13#include "TableGenBackends.h"
14#include "llvm/ADT/StringSet.h"
15#include "llvm/TableGen/Error.h"
16#include "llvm/TableGen/TableGenBackend.h"
17
18#include <sstream>
19
20using namespace llvm;
21
22static std::string TemplateNameList;
23static std::string CreateBuiltinTemplateParameterList;
24
25static llvm::StringSet<> BuiltinClasses;
26
27namespace {
28struct ParserState {
29 size_t UniqueCounter = 0;
30 size_t CurrentDepth = 0;
31 bool EmittedSizeTInfo = false;
32 bool EmittedUint32TInfo = false;
33};
34
35std::pair<std::string, std::string>
36ParseTemplateParameterList(ParserState &PS,
37 ArrayRef<const Record *> TemplateArgs) {
38 llvm::SmallVector<std::string, 4> Params;
39 llvm::StringMap<std::string> TemplateNameToParmName;
40
41 std::ostringstream Code;
42 Code << std::boolalpha;
43
44 size_t Position = 0;
45 for (const Record *Arg : TemplateArgs) {
46 std::string ParmName = "Parm" + std::to_string(val: PS.UniqueCounter++);
47 if (Arg->isSubClassOf(Name: "Template")) {
48 ++PS.CurrentDepth;
49 auto [TemplateCode, TPLName] =
50 ParseTemplateParameterList(PS, TemplateArgs: Arg->getValueAsListOfDefs(FieldName: "Args"));
51 --PS.CurrentDepth;
52 Code << TemplateCode << " auto *" << ParmName
53 << " = TemplateTemplateParmDecl::Create(C, DC, SourceLocation(), "
54 << PS.CurrentDepth << ", " << Position++
55 << ", /*ParameterPack=*/false, /*Id=*/nullptr, "
56 "/*Kind=*/TNK_Type_template, /*Typename=*/false, "
57 << TPLName << ");\n";
58 } else if (Arg->isSubClassOf(Name: "Class")) {
59 Code << " auto *" << ParmName
60 << " = TemplateTypeParmDecl::Create(C, DC, SourceLocation(), "
61 "SourceLocation(), "
62 << PS.CurrentDepth << ", " << Position++
63 << ", /*Id=*/nullptr, /*Typename=*/false, "
64 << Arg->getValueAsBit(FieldName: "IsVariadic") << ");\n";
65 } else if (Arg->isSubClassOf(Name: "NTTP")) {
66 auto Type = Arg->getValueAsString(FieldName: "TypeName");
67
68 if (!TemplateNameToParmName.contains(Key: Type.str()))
69 PrintFatalError(Msg: "Unknown Type Name");
70
71 auto TSIName = "TSI" + std::to_string(val: PS.UniqueCounter++);
72 Code << " auto *" << TSIName << " = C.getTrivialTypeSourceInfo(QualType("
73 << TemplateNameToParmName[Type.str()] << "->getTypeForDecl(), 0));\n"
74 << " auto *" << ParmName
75 << " = NonTypeTemplateParmDecl::Create(C, DC, SourceLocation(), "
76 "SourceLocation(), "
77 << PS.CurrentDepth << ", " << Position++ << ", /*Id=*/nullptr, "
78 << TSIName << "->getType(), " << Arg->getValueAsBit(FieldName: "IsVariadic")
79 << ", " << TSIName << ");\n";
80 } else if (Arg->isSubClassOf(Name: "BuiltinNTTP")) {
81 std::string SourceInfo;
82 if (Arg->getValueAsString(FieldName: "TypeName") == "size_t") {
83 SourceInfo = "SizeTInfo";
84 if (!PS.EmittedSizeTInfo) {
85 Code << "TypeSourceInfo *SizeTInfo = "
86 "C.getTrivialTypeSourceInfo(C.getSizeType());\n";
87 PS.EmittedSizeTInfo = true;
88 }
89 } else if (Arg->getValueAsString(FieldName: "TypeName") == "uint32_t") {
90 SourceInfo = "Uint32TInfo";
91 if (!PS.EmittedUint32TInfo) {
92 Code << "TypeSourceInfo *Uint32TInfo = "
93 "C.getTrivialTypeSourceInfo(C.UnsignedIntTy);\n";
94 PS.EmittedUint32TInfo = true;
95 }
96 } else {
97 PrintFatalError(Msg: "Unknown Type Name");
98 }
99 Code << " auto *" << ParmName
100 << " = NonTypeTemplateParmDecl::Create(C, DC, SourceLocation(), "
101 "SourceLocation(), "
102 << PS.CurrentDepth << ", " << Position++ << ", /*Id=*/nullptr, "
103 << SourceInfo
104 << "->getType(), "
105 "/*ParameterPack=*/false, "
106 << SourceInfo << ");\n";
107 } else {
108 PrintFatalError(Msg: "Unknown Argument Type");
109 }
110
111 TemplateNameToParmName[Arg->getValueAsString(FieldName: "Name").str()] = ParmName;
112 Params.emplace_back(Args: std::move(ParmName));
113 }
114
115 auto TPLName = "TPL" + std::to_string(val: PS.UniqueCounter++);
116 Code << " auto *" << TPLName
117 << " = TemplateParameterList::Create(C, SourceLocation(), "
118 "SourceLocation(), {";
119
120 if (Params.empty()) {
121 PrintFatalError(
122 Msg: "Expected at least one argument in template parameter list");
123 }
124
125 bool First = true;
126 for (const auto &e : Params) {
127 if (First) {
128 First = false;
129 Code << e;
130 } else {
131 Code << ", " << e;
132 }
133 }
134 Code << "}, SourceLocation(), nullptr);\n";
135
136 return {std::move(Code).str(), std::move(TPLName)};
137}
138
139static void
140EmitCreateBuiltinTemplateParameterList(std::vector<const Record *> TemplateArgs,
141 StringRef Name) {
142 using namespace std::string_literals;
143 CreateBuiltinTemplateParameterList +=
144 "case BTK"s + std::string{Name} + ": {\n"s;
145
146 ParserState PS;
147 auto [Code, TPLName] = ParseTemplateParameterList(PS, TemplateArgs);
148 CreateBuiltinTemplateParameterList += Code + "\n return " + TPLName + ";\n";
149
150 CreateBuiltinTemplateParameterList += " }\n";
151}
152
153void EmitBuiltinTemplate(const Record *BuiltinTemplate) {
154 auto Class = BuiltinTemplate->getType()->getAsString();
155 auto Name = BuiltinTemplate->getName();
156
157 std::vector<const Record *> TemplateHead =
158 BuiltinTemplate->getValueAsListOfDefs(FieldName: "TemplateHead");
159
160 EmitCreateBuiltinTemplateParameterList(TemplateArgs: TemplateHead, Name);
161
162 TemplateNameList += Class + "(";
163 TemplateNameList += Name;
164 TemplateNameList += ")\n";
165
166 BuiltinClasses.insert(key: Class);
167}
168
169void EmitDefaultDefine(llvm::raw_ostream &OS, StringRef Name) {
170 OS << "#ifndef " << Name << "\n";
171 OS << "#define " << Name << "(NAME)" << " " << "BuiltinTemplate"
172 << "(NAME)\n";
173 OS << "#endif\n\n";
174}
175
176void EmitUndef(llvm::raw_ostream &OS, StringRef Name) {
177 OS << "#undef " << Name << "\n";
178}
179} // namespace
180
181void clang::EmitClangBuiltinTemplates(const llvm::RecordKeeper &Records,
182 llvm::raw_ostream &OS) {
183 emitSourceFileHeader(Desc: "Tables and code for Clang's builtin templates", OS);
184
185 for (const auto *Builtin :
186 Records.getAllDerivedDefinitions(ClassName: "BuiltinTemplate"))
187 EmitBuiltinTemplate(BuiltinTemplate: Builtin);
188
189 for (const auto &ClassEntry : BuiltinClasses) {
190 StringRef Class = ClassEntry.getKey();
191 if (Class == "BuiltinTemplate")
192 continue;
193 EmitDefaultDefine(OS, Name: Class);
194 }
195
196 OS << "#if defined(CREATE_BUILTIN_TEMPLATE_PARAMETER_LIST)\n"
197 << CreateBuiltinTemplateParameterList
198 << "#undef CREATE_BUILTIN_TEMPLATE_PARAMETER_LIST\n#else\n"
199 << TemplateNameList << "#undef BuiltinTemplate\n#endif\n";
200
201 for (const auto &ClassEntry : BuiltinClasses) {
202 StringRef Class = ClassEntry.getKey();
203 if (Class == "BuiltinTemplate")
204 continue;
205 EmitUndef(OS, Name: Class);
206 }
207}
208