
This is a first pass at implementing [P2841R7](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2841r7.pdf). The implementation is far from complete; however, I'm aiming to do that in chunks, to make our lives easier. In particular, this does not implement - Subsumption - Mangling - Satisfaction checking is minimal as we should focus on #141776 first (note that I'm currently very stuck) FTM, release notes, status page, etc, will be updated once the feature is more mature. Given the state of the feature, it is not yet allowed in older language modes. Of note: - Mismatches between template template arguments and template template parameters are a bit wonky. This is addressed by #130603 - We use `UnresolvedLookupExpr` to model template-id. While this is pre-existing, I have been wondering if we want to introduce a different OverloadExpr subclass for that. I did not make the change in this patch.
208 lines
7.0 KiB
C++
208 lines
7.0 KiB
C++
//=- ClangBuiltinsEmitter.cpp - Generate Clang builtin templates-*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This tablegen backend emits Clang's builtin templates.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "TableGenBackends.h"
|
|
#include "llvm/ADT/StringSet.h"
|
|
#include "llvm/TableGen/Error.h"
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
|
|
|
#include <sstream>
|
|
|
|
using namespace llvm;
|
|
|
|
static std::string TemplateNameList;
|
|
static std::string CreateBuiltinTemplateParameterList;
|
|
|
|
static llvm::StringSet<> BuiltinClasses;
|
|
|
|
namespace {
|
|
struct ParserState {
|
|
size_t UniqueCounter = 0;
|
|
size_t CurrentDepth = 0;
|
|
bool EmittedSizeTInfo = false;
|
|
bool EmittedUint32TInfo = false;
|
|
};
|
|
|
|
std::pair<std::string, std::string>
|
|
ParseTemplateParameterList(ParserState &PS,
|
|
ArrayRef<const Record *> TemplateArgs) {
|
|
llvm::SmallVector<std::string, 4> Params;
|
|
llvm::StringMap<std::string> TemplateNameToParmName;
|
|
|
|
std::ostringstream Code;
|
|
Code << std::boolalpha;
|
|
|
|
size_t Position = 0;
|
|
for (const Record *Arg : TemplateArgs) {
|
|
std::string ParmName = "Parm" + std::to_string(PS.UniqueCounter++);
|
|
if (Arg->isSubClassOf("Template")) {
|
|
++PS.CurrentDepth;
|
|
auto [TemplateCode, TPLName] =
|
|
ParseTemplateParameterList(PS, Arg->getValueAsListOfDefs("Args"));
|
|
--PS.CurrentDepth;
|
|
Code << TemplateCode << " auto *" << ParmName
|
|
<< " = TemplateTemplateParmDecl::Create(C, DC, SourceLocation(), "
|
|
<< PS.CurrentDepth << ", " << Position++
|
|
<< ", /*ParameterPack=*/false, /*Id=*/nullptr, "
|
|
"/*Kind=*/TNK_Type_template, /*Typename=*/false, "
|
|
<< TPLName << ");\n";
|
|
} else if (Arg->isSubClassOf("Class")) {
|
|
Code << " auto *" << ParmName
|
|
<< " = TemplateTypeParmDecl::Create(C, DC, SourceLocation(), "
|
|
"SourceLocation(), "
|
|
<< PS.CurrentDepth << ", " << Position++
|
|
<< ", /*Id=*/nullptr, /*Typename=*/false, "
|
|
<< Arg->getValueAsBit("IsVariadic") << ");\n";
|
|
} else if (Arg->isSubClassOf("NTTP")) {
|
|
auto Type = Arg->getValueAsString("TypeName");
|
|
|
|
if (!TemplateNameToParmName.contains(Type.str()))
|
|
PrintFatalError("Unknown Type Name");
|
|
|
|
auto TSIName = "TSI" + std::to_string(PS.UniqueCounter++);
|
|
Code << " auto *" << TSIName << " = C.getTrivialTypeSourceInfo(QualType("
|
|
<< TemplateNameToParmName[Type.str()] << "->getTypeForDecl(), 0));\n"
|
|
<< " auto *" << ParmName
|
|
<< " = NonTypeTemplateParmDecl::Create(C, DC, SourceLocation(), "
|
|
"SourceLocation(), "
|
|
<< PS.CurrentDepth << ", " << Position++ << ", /*Id=*/nullptr, "
|
|
<< TSIName << "->getType(), " << Arg->getValueAsBit("IsVariadic")
|
|
<< ", " << TSIName << ");\n";
|
|
} else if (Arg->isSubClassOf("BuiltinNTTP")) {
|
|
std::string SourceInfo;
|
|
if (Arg->getValueAsString("TypeName") == "size_t") {
|
|
SourceInfo = "SizeTInfo";
|
|
if (!PS.EmittedSizeTInfo) {
|
|
Code << "TypeSourceInfo *SizeTInfo = "
|
|
"C.getTrivialTypeSourceInfo(C.getSizeType());\n";
|
|
PS.EmittedSizeTInfo = true;
|
|
}
|
|
} else if (Arg->getValueAsString("TypeName") == "uint32_t") {
|
|
SourceInfo = "Uint32TInfo";
|
|
if (!PS.EmittedUint32TInfo) {
|
|
Code << "TypeSourceInfo *Uint32TInfo = "
|
|
"C.getTrivialTypeSourceInfo(C.UnsignedIntTy);\n";
|
|
PS.EmittedUint32TInfo = true;
|
|
}
|
|
} else {
|
|
PrintFatalError("Unknown Type Name");
|
|
}
|
|
Code << " auto *" << ParmName
|
|
<< " = NonTypeTemplateParmDecl::Create(C, DC, SourceLocation(), "
|
|
"SourceLocation(), "
|
|
<< PS.CurrentDepth << ", " << Position++ << ", /*Id=*/nullptr, "
|
|
<< SourceInfo
|
|
<< "->getType(), "
|
|
"/*ParameterPack=*/false, "
|
|
<< SourceInfo << ");\n";
|
|
} else {
|
|
PrintFatalError("Unknown Argument Type");
|
|
}
|
|
|
|
TemplateNameToParmName[Arg->getValueAsString("Name").str()] = ParmName;
|
|
Params.emplace_back(std::move(ParmName));
|
|
}
|
|
|
|
auto TPLName = "TPL" + std::to_string(PS.UniqueCounter++);
|
|
Code << " auto *" << TPLName
|
|
<< " = TemplateParameterList::Create(C, SourceLocation(), "
|
|
"SourceLocation(), {";
|
|
|
|
if (Params.empty()) {
|
|
PrintFatalError(
|
|
"Expected at least one argument in template parameter list");
|
|
}
|
|
|
|
bool First = true;
|
|
for (const auto &e : Params) {
|
|
if (First) {
|
|
First = false;
|
|
Code << e;
|
|
} else {
|
|
Code << ", " << e;
|
|
}
|
|
}
|
|
Code << "}, SourceLocation(), nullptr);\n";
|
|
|
|
return {std::move(Code).str(), std::move(TPLName)};
|
|
}
|
|
|
|
static void
|
|
EmitCreateBuiltinTemplateParameterList(std::vector<const Record *> TemplateArgs,
|
|
StringRef Name) {
|
|
using namespace std::string_literals;
|
|
CreateBuiltinTemplateParameterList +=
|
|
"case BTK"s + std::string{Name} + ": {\n"s;
|
|
|
|
ParserState PS;
|
|
auto [Code, TPLName] = ParseTemplateParameterList(PS, TemplateArgs);
|
|
CreateBuiltinTemplateParameterList += Code + "\n return " + TPLName + ";\n";
|
|
|
|
CreateBuiltinTemplateParameterList += " }\n";
|
|
}
|
|
|
|
void EmitBuiltinTemplate(const Record *BuiltinTemplate) {
|
|
auto Class = BuiltinTemplate->getType()->getAsString();
|
|
auto Name = BuiltinTemplate->getName();
|
|
|
|
std::vector<const Record *> TemplateHead =
|
|
BuiltinTemplate->getValueAsListOfDefs("TemplateHead");
|
|
|
|
EmitCreateBuiltinTemplateParameterList(TemplateHead, Name);
|
|
|
|
TemplateNameList += Class + "(";
|
|
TemplateNameList += Name;
|
|
TemplateNameList += ")\n";
|
|
|
|
BuiltinClasses.insert(Class);
|
|
}
|
|
|
|
void EmitDefaultDefine(llvm::raw_ostream &OS, StringRef Name) {
|
|
OS << "#ifndef " << Name << "\n";
|
|
OS << "#define " << Name << "(NAME)" << " " << "BuiltinTemplate"
|
|
<< "(NAME)\n";
|
|
OS << "#endif\n\n";
|
|
}
|
|
|
|
void EmitUndef(llvm::raw_ostream &OS, StringRef Name) {
|
|
OS << "#undef " << Name << "\n";
|
|
}
|
|
} // namespace
|
|
|
|
void clang::EmitClangBuiltinTemplates(const llvm::RecordKeeper &Records,
|
|
llvm::raw_ostream &OS) {
|
|
emitSourceFileHeader("Tables and code for Clang's builtin templates", OS);
|
|
|
|
for (const auto *Builtin :
|
|
Records.getAllDerivedDefinitions("BuiltinTemplate"))
|
|
EmitBuiltinTemplate(Builtin);
|
|
|
|
for (const auto &ClassEntry : BuiltinClasses) {
|
|
StringRef Class = ClassEntry.getKey();
|
|
if (Class == "BuiltinTemplate")
|
|
continue;
|
|
EmitDefaultDefine(OS, Class);
|
|
}
|
|
|
|
OS << "#if defined(CREATE_BUILTIN_TEMPLATE_PARAMETER_LIST)\n"
|
|
<< CreateBuiltinTemplateParameterList
|
|
<< "#undef CREATE_BUILTIN_TEMPLATE_PARAMETER_LIST\n#else\n"
|
|
<< TemplateNameList << "#undef BuiltinTemplate\n#endif\n";
|
|
|
|
for (const auto &ClassEntry : BuiltinClasses) {
|
|
StringRef Class = ClassEntry.getKey();
|
|
if (Class == "BuiltinTemplate")
|
|
continue;
|
|
EmitUndef(OS, Class);
|
|
}
|
|
}
|